Текущий архив: 2005.01.02;
Скачать: CL | DM;
Вниз
Не нравится мне мой код Найти похожие ветки
← →
TUser © (2004-12-17 15:16) [0]Есть предковые классы
TDynElement = class
end;
TDynArray = class
private
FCount: integer;
FAutoIncrement: boolean;
FAutoCreate: boolean;
FArray: array of TDynElement;
procedure wrLength(Value:integer);
public
constructor Create;
destructor Destroy; override;
function rItems(Index:integer):TDynElement;
procedure wrItems(Index:integer; Value:TDynElement);
procedure CreateItem(Index:integer); virtual; abstract;
property Length:integer read FCount write wrLength;
property AutoIncrement:boolean read FAutoIncrement write FAutoIncrement default true;
property AutoCreate:boolean read FAutoCreate write FAutoCreate default true;
end;
и куча наследников (уже несколько десятков набралось)
TDyn1 = class(TDynElement)
public
{any properties to storage}
end;
TDyn1Array = class(TDynArray)
private
function rItems(Index:integer):TFound;
procedure wrItems(Index:integer; Value:TFound);
public
procedure CreateItem(Index:integer); override;
property Items[Index:integer]:TFound read rItems write wrItems; default;
end;
Реализауия такаяprocedure TDynArray.wrLength(Value:integer);
var Power2: integer;
f:boolean;
begin
if Value < 0 then begin
PutInConsol("procedure TDynArray.wrLength(Value:integer);");
PutInConsol("Value = "+inttostr(Value));
end
else begin
if Value > system.length(FArray) then begin
f:=true; Power2:=512;
while f and (Power2 >= 8) do
if Value >= Power2 then
f:=false
else Power2 := Power2 div 2;
if f then Power2:=1;
if Value mod Power2 = 0 then
Power2:=Value
else
Power2:=(Value div Power2) * Power2 + Power2;
SetLength(FArray,Power2);
end;
FCount:=Value;
end;
end;
function TDynArray.rItems(Index:integer):TDynElement;
begin
if (Index < 0) or (Index >= FCount) then begin
PutInConsol("function TDynArray.rItems(Index:integer):pointer;");
PutInConsol("Index = "+inttostr(Index));
PutInConsol("FCount = "+inttostr(FCount));
end else begin
if FArray[Index] = nil then
if FAutoCreate then
CreateItem(Index);
result:=FArray[Index];
end;
end;
procedure TDynArray.wrItems(Index:integer; Value:TDynElement);
begin
if (Index < 0) or (Index >= FCount) then
if FAutoIncrement and (Index > 0) then
wrLength(Index+1)
else begin
PutInConsol("procedure TDynArray.wrItems(Index:integer; Value:pointer);");
PutInConsol("Index = "+inttostr(Index));
Exit; // :((
end;
FArray[Index]:=Value;
end;
constructor TDynArray.Create;
begin
inherited;
SetLength(FArray,0);
FCount:=0;
end;
destructor TDynArray.Destroy;
var i: integer;
begin
for i:=0 to system.length(FArray)-1 do
FArray[i].Free;
SetLength(FArray,0);
inherited;
end;
function TDyn1Array.rItems(Index:integer):TDyn1;
begin
result:=TDyn1(inherited rItems(Index));
end;
procedure TDyn1Array.wrItems(Index:integer; Value:TDyn1);
begin
inherited wrItems(Index,Value);
end;
procedure TDyn1Array.CreateItem(Index:integer);
begin
Items[Index]:=TDyn1.Create;
end;
Но когда уже есть TDyn1, ..., TDyn125, то складывается впечатление, что я изобретаю какую-то ерунду. Должен быть какой-нибудь способ, чтобы создать базывай класс, а в наследниках переписать тип для Items. Пробовал сclass of
, но не уверен, что это то, что мне надо. Какие есть соображения типа "переписать все нафик"?
← →
Anatoly Podgoretsky © (2004-12-17 15:24) [1]И мне твой код не нравится :-)
← →
TUser © (2004-12-17 15:29) [2]
> Anatoly Podgoretsky © (17.12.04 15:24) [1]
Как это сделать не через j.опу?
← →
Alexander Panov © (2004-12-17 15:33) [3]Ты ж не привел пример нескольких наследников, чтобы увидеть, чем они различаются...
← →
Digitman © (2004-12-17 15:35) [4]
> Как это сделать не через j.опу?
для этого нужно понять, как отличается, по твоей логике, поведение методов классов-наследников от одноименных (однотипных) методов класса-предка ..
← →
Anatoly Podgoretsky © (2004-12-17 15:36) [5]А что ты хочешь?
← →
Anatoly Podgoretsky © (2004-12-17 15:37) [6]И зачем тогда задаешь вопрос Не нравится мне мой код , ты уж задай правильный :-)
А так можно обсуждать только одно нравится или нет.
← →
REA (2004-12-17 15:39) [7]Если вопрос о шаблонах, то в D2005 что-то есть, а в более ранних версиях можно сделать через Include.
← →
TUser © (2004-12-17 17:05) [8]Что мне надо? Динамический массив, который обладает такими св-вами:
1. Умное выделение памяти - большими блоками (как в TList"е).
2. Несокращение размера после его укорачивания.
Эти пп. позволяют избежать большого кол-ва перераспределений памяти. Например, если сначала пришло 3 раза подряд запрос на 1 элемент - будет 3 раза выделено по элементу, если потом придет запрос на 25 элементов - будет выделено 32-3=29. Если потом попросить еще 2 элемента - то просто увеличится счетчик FCount. Если потом уменьшить длину на 10 - то опять же просто FCount изменится.
Также надо
3. Автоматическое создание и удаление объектов.
4. Контроль типов при добавлении элементов. Вот здесь и проблема. Для работы с каждым типом создаем своего наследника. Все типы, с которыми надо работать, - наследники TDynElement. Надо в наследниках реализовать методы wrItem и rItem таким образом, чтобы они принимали правильный (для данного наследника тип). Но не могу же я написать
procedure wrItem(Index:integer; Value:TDynElement); virtual;
...
TDyn1 = class(TDynElement)
...
procedure wrItem(Index:integer; Value:TDyn1); override;
...
тогда будет Differs from previous declaration. Подозреваю, что должен существовать какой-нибудь простой способ сделать что-то типа такого класса, у которого есть св-во Items[] с элементами типа TDynElement, а у его наследников методы доступа к этому полю работают не с TDynElement, а с наследниками TDynElement"а. Т.е. в приведенном коде это как раз и реализовано, но получается дофига почти одинаковых процедур типа
function TDyn1Array.rItems(Index:integer):TDyn1;
begin
result:=TDyn1(inherited rItems(Index));
end;
единственная разница в которых состоит в том, к какому типу приводится результат. Хотелось бы делать это "малой кровью" - например, прописав какое-нибудь св-во у наследников, и не переписывая методы базового класса. Вот так.
← →
Alexander Panov © (2004-12-17 17:17) [9]TUser © (17.12.04 17:05) [8]
тогда будет Differs from previous declaration.
Попробуй воспользоваться директивой overload ?
← →
TUser © (2004-12-17 17:18) [10]
> Попробуй воспользоваться директивой overload ?
Так все равно придется прописывать реализацию этого метода. А этого хочется избежать ... если возможно, конечно.
← →
tesseract (2004-12-17 17:24) [11]А почему бы вместо Array не использовать Tlist?
И насчёт наследников - Наследники могут вызывать методы родителей и любой класс-наследник можно трактовать как родителя через TypeCasting - Посмотри на реализацию Tfield и его наследников - и методы TField типа AsInteger. Или на замечательный тип Tstrings - он в VCL используется обширно
← →
TUser © (2004-12-17 17:31) [12]Это и есть почти TList, только еще добавлен контроль типов и автоматическое создание/удаление объектов, на которые храняться ссылки.
Хочу именно избежать переписывания методов. В идеале написать что-нибудь типа
TDesc = class(TDynArray)
FNeededType: {здесь написать требуемый тип}
end;
и все. Чтобы после этого наследник стал работаь с объектами только указанного типа.
← →
GuAV © (2004-12-17 22:19) [13]2 TUser ©
IMHO один класс для списка и оператор as (или даже явное привидение типов) в зависимости от типа элемента уже по месту использования класса.
← →
GuAV © (2004-12-17 22:20) [14]А лучше ничего не придумаешь. IMHO.
← →
Almaz © (2004-12-18 07:34) [15]
> Т.е. в приведенном коде это как раз и реализовано, но получается
> дофига почти одинаковых процедур типа
> function TDyn1Array.rItems(Index:integer):TDyn1;
> begin
> result:=TDyn1(inherited rItems(Index));
> end;
А почему это преобразование типа не выполнять в коде по месту приложения ? Т.е. там где надо писатьTDyn1(DynArray.rItems(I))
?
Единственная проблема, котороя может возникнуть - это методCreateItem
который должен создавать элемент заданного типа, но это можно решить следующим образом:type
TDynElement = class
end;
TDynElementClass = class of TDynElement;
TDynArray = class
private
FDynElementClass: TDynElementClass;
...
public
constructor Create(DynElementClass: TDynElementClass);
procedure CreateItem(Index:integer);
...
end;
constructor TDynArray.Create(DynElementClass: TDynElementClass);
begin
FDynElementClass := DynElementClass;
...
end;
procedure TDynArray.CreateItem(Index: Integer);
begin
Items[Index] := FDynElementClass.Create;
end;
...
DynArray := TDynArray.Create(TDyn1);
Удачи.
← →
TUser © (2004-12-18 11:56) [16]
> GuAV © (17.12.04 22:20) [14]
> Almaz © (18.12.04 07:34) [15]
Нет. Это еще хуже получится - везде, где используется объект такого класса писать TDynN(...). Уж лучше один модуль с неск. десятками почти одинаковых методов. Жаль, но видимо, лучше действительно ничего не придумать.
Всем спасибо.
← →
Kolan © (2004-12-18 14:50) [17]могу по оформлению замечания сделать :)
property Length:integer read FCount write wrLength;
property Length:integer read FCount write SetLength;
А если нада для read то будет GetLength...
wrLength - по моему это называется венгерская нотация её следует использовать для перечисляемого типа.
Например
TErrorType =
(
etUnKnownCommand // Не известная команда.
);
f:boolean;
Переменных состояших из одной буквы следует избегать или писать с большой буквы.
F: Boolean;
и пробелы.
I := I + 1;
:)))
← →
TUser © (2004-12-18 14:55) [18]
> Kolan © (18.12.04 14:50) [17]
Да, мне это каждый раз говорят, когда я свой код выкладываю. А я привык к wr и r. Во всех программах у меня так, и нормально. Должен же я быть хоть в чем-то оригинален.
> Переменных состояших из одной буквы следует избегать или
> писать с большой буквы.
Также следует избегать операторных скобок из одной буквы - наверное поэтому я и пишу на паскале. :))
> и пробелы.
Это на Бейсике.
← →
Kolan © (2004-12-18 15:12) [19]Я вообше 2 месяца назад писал так
funtion Get_Root_Dir(): integer;
О отступах даже не знал. Потом прочитал "Стандарты стилевого оформления фирмы Borland", кажись так называлась. Так там почти сразу написанно. -Переходите сразу на правильное оформление и вы оч. быстро привыкните и точно за 1 маленmre. программу привык. :)
> Также следует избегать операторных скобок из одной буквы
Как это?
> Должен же я быть хоть в чем-то оригинален.
Это да. Я почти все модули и классы я называю с буквы K.
:)
← →
TUser © (2004-12-18 15:30) [20]
> > Также следует избегать операторных скобок из одной буквы
>
> Как это?
Я просто хотел сказать, что аргументация против переменных из одной буквы, мне кажется слабой. Таким же образом я могу доказать, что Паскать в 3-5 раз круче, чем Си.
← →
begin...end © (2004-12-18 15:34) [21]> [20] TUser © (18.12.04 15:30)
> Таким же образом я могу доказать, что Паскать в 3-5 раз
> круче, чем Си.
Доказательства не требуются, т.к. это очевидно :-)
Страницы: 1 вся ветка
Текущий архив: 2005.01.02;
Скачать: CL | DM;
Память: 0.53 MB
Время: 0.027 c