Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.10.23;
Скачать: CL | DM;

Вниз

Как изменить тип создоваемого объекта в методе предка.   Найти похожие ветки 

 
Kolan ©   (2005-09-26 16:02) [0]

Здравствуйте,
 Есть у меня стек:
TStack = class(TCustomList)
 private
 protected
 public
   function GetListAsString: string; override;
   function GetListAsStrings: TStrings; override;
   function Add(Data: TNodeData): Boolean; override;
   function Extract: TNodeData; override;
   constructor Create(FormHandle: THandle); override;
   destructor Destroy; override;
 end;

Вот его метод Add

function TStack.Add(Data: TNodeData): Boolean;
var
 Node: TCustomNode;
begin
 inherited Add(Data);
 Node := TCustomNode.Create;
 try
   Node.Data := Data;
   if Head <> nil then
     Node.FNext := Head;
   Head := Node;
   Result := True;
 except
   Result := False;
 end;    
end;


Теперь я хочу сделать такойже стек но элементы которого будут иметь две ссылки:

TDoubleTreeNode = class(TCustomNode)
 private
   FParent: TDoubleTreeNode;
 protected
 public
   constructor Create; override;
   destructor Destroy; override;
 end;


Как написать наследника от стека, поддерживающего элементы типа TDoubleTreeNode

Неужели для того, чтобы изменить
Node := TCustomNode.Create;
на
Node := TDoubleTreeNode.Create;
Придётся переписать весь код метода Add. (Переписать я его смогу ессесно, интересно узнать как правильно спроектировать классы.)


 
Kolan ©   (2005-09-26 17:18) [1]

Блин опять похоже никто не понял ничего
Я имею в виду что в предке будет

function TStack.Add(Data: TNodeData): Boolean;
var
Node: TCustomNode;
begin
inherited Add(Data);
Node := TCustomNode.Create;
try
  Node.Data := Data;
  if Head <> nil then
    Node.FNext := Head;
  Head := Node;
  Result := True;
except
  Result := False;
end;    
end;


А в потомке

function TStack.Add(Data: TNodeData): Boolean;
var
Node: TCustomNode;
begin
inherited Add(Data);
Node := TDoubleTreeNode.Create;
try
  Node.Data := Data;
  if Head <> nil then
    Node.FNext := Head;
  Head := Node;
  Result := True;
except
  Result := False;
end;    
end;

Это если переписать. Я вно я гдето ошибся. Как сделать так чтобы можно было
в качестве эл списка создавать  любого потомка TCustomNode

Может
inherited Add
а потом
преобразовать node из TCustomNode в TDoubleTreeNode
Только как???


 
jack128 ©   (2005-09-26 17:30) [2]

TStack = class(TCustomList)
private
protected
 function CreateNode: TCustomNode; virtual;
public
  function GetListAsString: string; override;
  function GetListAsStrings: TStrings; override;
  function Add(Data: TNodeData): Boolean; override;
  function Extract: TNodeData; override;
  constructor Create(FormHandle: THandle); override;
  destructor Destroy; override;
end;

TStack2 = class(TStack)
protected
 function CreateNode: TCustomNode; override;
end;

function TStack.CreateNode: TCustomNode;
begin
 Result := TCustomNode.Create;
end;

function TStack.Add(Data: TNodeData): Boolean;
var
Node: TCustomNode;
begin
inherited Add(Data);
Node := CreateNode;
try
 Node.Data := Data;
 if Head <> nil then
   Node.FNext := Head;
 Head := Node;
 Result := True;
except
 Result := False;
end;    
end;

function TStack2.CreateNode: TCustomNode;
begin
 Result := TDoubleTreeNode.Create;
end;


 
jack128 ©   (2005-09-26 17:34) [3]

Или можно сделать событие OnCreateNode в котором создовать нужный узел. Тогда не придется для каждого наследника TCustomNode создовать наследника TStack. Либо, если TCustomNode имеет виртуальный конструктор, то можно создать свойство NodeClass: TCustomNodeClass; тогда даже обработчик события не нужно будет писать.  Но при прочих равных, я предпочитаю вариант из поста [2]


 
umbra ©   (2005-09-26 19:16) [4]

Можно


TCustomListNode = class of TCustomNode;

TStack = class(TCustomList)
private
protected
function CreateNode: TCustomNode; virtual;
public
 function GetListAsString: string; override;
 function GetListAsStrings: TStrings; override;
 function Add(Node: TCustomNodeClass; Data: TNodeData): Boolean; override;
 function Extract: TNodeData; override;
 constructor Create(FormHandle: THandle); override;
 destructor Destroy; override;
end;

function TStack.Add(ANode: TCustomNodeClass; Data: TNodeData): Boolean;
var
Node: TCustomNode;
begin
inherited Add(Data);
Node := ANode.Create;
try
 Node.Data := Data;
 if Head <> nil then
   Node.FNext := Head;
 Head := Node;
 Result := True;
except
 Result := False;
end;    
end;


 
Kolan ©   (2005-09-26 20:44) [5]

jack128 ©   (26.09.05 17:34) [3]
Понял, большой Сенкс :)

umbra ©   (26.09.05 19:16) [4]
OK, но воспользуюсь [2]


 
Kolan ©   (2005-09-26 21:27) [6]

Ещё один вопрос. Сразу не учёл...
 При добавлении в стек с "двойными" элементами мне надо присовоить значение FParent поэтому метод Add выглядит так:
function Add(Data: TNodeData; ParentNode: TCustomNode): Boolean;
Осюда 3 вопроса

1. Как правильно это описать? После прочтения справки думаю что так: В предке
function Add(Data: TNodeData): Boolean; overload; override;
а в потомке
function Add(Data: TNodeData; ParentNode: TCustomNode): Boolean; reintroduce; overload;
Но не уверен, а компилируется и без overload; и без reintroduce;.

2. :))) Как теперь использовать код наследника. Сделал как советовал, теперь выглядит так: jack128 ©
function TStack.Add(Data: TNodeData): Boolean;
var
 Node: TCustomNode;
begin
 inherited Add(Data);
 Node := CreateNode;
 try
   Node.Data := Data;
   if Head <> nil then
     Node.FNext := Head;
   Head := Node;
   Result := True;
 except
   Result := False;
 end;
end;


3. Как присвоить переданный ParentNode. Т.е.:
Так
(1)var
 P: TCustomNode;
begin
 P := ParentNode;
(ParentNode ведь создан не как TCustomNode)
или так
(2)
P := (ParentNode as TDoubleTreeNode);

Я думаю что правильно (1), вроде по идее указатель и в африке указатель...

----
С уважением, Kolan


 
Kolan ©   (2005-09-26 22:23) [7]

Решил заодно и список сделать дву связным. Поэтому сделал его потом ком не стека а очереди
TDoubleTreeList = class(TQueue)
 private
 protected
   function CreateNode: TCustomNode; override;
 public
   function Add(Data: TNodeData; ParentNode: TCustomNode): Boolean; reintroduce; overload;
 end;


А элемент выглядит так:
TDoubleTreeNode = class(TCustomNode)
 private
   FPrevious: TDoubleTreeNode;
   FParent: TDoubleTreeNode;
 protected
 public
   constructor Create; override;
   destructor Destroy; override;
   property Parent: TDoubleTreeNode read FParent write FParent;
   property Previous: TDoubleTreeNode read FPrevious write FPrevious;
 end;

Добавилась ссылка на предыдущий.

Тк в очереди Add добовляет  конец
var
 Node: TCustomNode;
begin
 inherited Add(Data);
 Node := CreateNode;
 try
   Node.Data := Data;
   if Head <> nil then
     Node.FNext := Head
   else
     Tail := Node;
   Head := Node;
   Result := True;
 except
    Result := False;
 end;
end;


У нового двухсвязного списка сделал Add так
function TDoubleTreeList.Add(Data: TNodeData;
 ParentNode: TCustomNode): Boolean;
begin
 inherited Add(Data);
 (Head as TDoubleTreeNode).FParent := (ParentNode as TDoubleTreeNode);
 if Head.Next <> nil then
   (Head as TDoubleTreeNode).Previous := (Head as TDoubleTreeNode);
end;


Жду ШО я сделал не так :)))


 
Kolan ©   (2005-09-27 21:20) [8]

up


 
jack128 ©   (2005-09-27 21:44) [9]

Kolan ©   (26.09.05 21:27) [6]
1. Как правильно это описать? После прочтения справки думаю что так: В предке
function Add(Data: TNodeData): Boolean; overload; override;
а в потомке
function Add(Data: TNodeData; ParentNode: TCustomNode): Boolean; reintroduce; overload;


зачем?? В предке function Add(Data: TNodeData): Boolean; а в наследнике function Add(Data: TNodeData; ParentNode: TCustomNode): Boolean; причем метод потомка описать так

Kolan ©   (26.09.05 22:23) [7]
Решил заодно и список сделать дву связным. Поэтому сделал его потом ком не стека а очереди

как всязаны двухсвязность или односвязность списка и стек или очередь??  Это понятия параллельные друг другу..
Kolan ©   (26.09.05 22:23) [7]
Добавилась ссылка на предыдущий.

а на предыдущий где?

Kolan ©   (26.09.05 22:23) [7]
TDoubleTreeNode = class(TCustomNode)
private
  FPrevious: TDoubleTreeNode;
  FParent: TDoubleTreeNode;
protected
public
  constructor Create; override;
  destructor Destroy; override;
  property Parent: TDoubleTreeNode read FParent write FParent;
  property Previous: TDoubleTreeNode read FPrevious write FPrevious;
end;

весело. так почему же ты объявил TDoubleTreeList.function Add(Data: TNodeData; ParentNode: TCustomNode): Boolean; если у тебя TDoubleTreeNode = class(TCustomNode)
private
  FPrevious: TDoubleTreeNode;
  FParent: TDoubleTreeNode;  ?  

еще как сие
Kolan ©   (26.09.05 22:23) [7]
Тк в очереди Add добовляет  конец

вяжется в этим кодом

var
Node: TCustomNode;
begin
inherited Add(Data);
Node := CreateNode;
try
  Node.Data := Data;
  if Head <> nil then
    Node.FNext := Head
  else
    Tail := Node;
  Head := Node; // безусловно помещает узел в НАЧАЛО списка


 
jack128 ©   (2005-09-27 21:46) [10]

jack128 ©   (27.09.05 21:44) [9]
Kolan ©   (26.09.05 22:23) [7]
Добавилась ссылка на предыдущий.
а на предыдущий где?

В смысле, а где ссылка на СЛЕДУЮЩИЙ элемент


 
Kolan ©   (2005-09-27 22:22) [11]

зачем?? В предке function Add(Data: TNodeData): Boolean; а в наследнике function Add(Data: TNodeData; ParentNode: TCustomNode): Boolean; причем метод потомка описать так

как всязаны двухсвязность или односвязность списка и стек или очередь??  Это понятия параллельные друг другу..

Это я просто чтобы вы знали, а то в начале один предок потом другой просто информация короче :)

весело. так почему же т...

Понятно поправлю..

В смысле, а где ссылка на СЛЕДУЮЩИЙ элемент

В предке:
TCustomNode = class
 private
   FData: TNodeData;
   FNext: TCustomNode;
 protected

 public
   procedure FillNode(Data: TNodeData; Next: Pointer);
   constructor Create;
   destructor Destroy; override;
   property Data: TNodeData read FData write FData;
   property Next: TCustomNode read FNext write FNext;
 published

 end;


безусловно помещает узел в НАЧАЛО списка
Да это и имелось в виду описка...


 
Игорь Шевченко ©   (2005-09-28 01:01) [12]

А почему бы у TCustomNode не сделать виртуальный метод AfterInsert, к примеру, передвать туда в качестве параметров Stack и еще что-то необходимое и пусть каждый наследник TCustomNode устанавливает в этом перекрытом методе сам все, что ему нужно...


 
Kolan ©   (2005-09-29 11:53) [13]

Игорь Шевченко ©   (28.09.05 01:01) [12]
Попробую.  

К суботе закончить планирую. Мож ещё чего-нибудь спрошу...
Благодарю за помощь  :)


 
Kolan ©   (2005-09-29 19:50) [14]

Ещё странная странность.
Есть переменная List
var
 MainForm: TMainForm;
 List: TCustomList;


Создан он как TStack

Если его уничтожить так:
 List.Free;
То после проверки на nil вызывается Destroy TObject"a
А если так:
 List.Destroy;
То всё нормально вызывается деструктор TStack

Код TCustomList мож понадобится.

TCustomList = class(TObject)
 private
   FCount: Integer;
   FHead: TCustomNode;
   FFormHandle: THandle;
 protected
 public
   function Add(Data: TNodeData): Boolean; overload; virtual;
   function Extract: TNodeData; virtual;
   function GetListAsString: string; virtual; abstract;
   procedure GetListAsStrings(var Strings: TStrings); virtual; abstract;
   constructor Create(FormHandle: THandle); virtual;
   destructor Destroy; virtual;
   property Count: Integer read FCount;
   property Head: TCustomNode read FHead write FHead;
   property FormaHandle: THandle read FFormHandle;
 end;


 
unknown   (2005-09-29 19:54) [15]

ибо destructor Destroy; virtual; вероятно )


 
Kolan ©   (2005-09-29 20:16) [16]

Объясни если можешь почему так происходит.


 
Игорь Шевченко ©   (2005-09-29 20:34) [17]


>   destructor Destroy; virtual;


destructor Destroy; override;


 
Kolan ©   (2005-09-29 20:59) [18]

Игорь Шевченко ©   (29.09.05 20:34) [17]
Извените за настойчивость, но непойму
1. Почему так вышло(словами).
2. destructor Destroy; override; это к чему ототносится?

Или ссылку с примерами для тупых.
Справку читал, Тайскейру читал.. мож плохо? :)


 
Игорь Шевченко ©   (2005-09-29 21:54) [19]


> Если его уничтожить так:
>  List.Free;
> То после проверки на nil вызывается Destroy TObject"a
> А если так:
>  List.Destroy;
> То всё нормально вызывается деструктор TStack


Потому что TObject.Free вызывает виртуальный деструктор TObject. Для того, чтобы вызывать деструктор твоего объекта, он должен быть объявлен с директивой override.


> 2. destructor Destroy; override; это к чему ототносится?
>  


К твоему классу. Тебе надо так объявить вместо destructor Destroy; virtual;
А сейчас ты своим объявлением добился того, что у твоего объекта два деструктора - один унаследованный от TObject, а второй привнесен тобой самим. При этом унаследованный деструктор виден только при приведении типа твоего объекта к TObject и больше нигде.

Кроме того, тебе нужно включить в опциях проекта на закладке Compiler флажки Show hints и Show warnings и писать программу так, чтобы с включенными флажками компилятор не сделал тебе ни одного замечания.
Только после этого задавать вопрос на форуме.


 
Kolan ©   (2005-10-01 11:58) [20]

Всё, доделал.
Спасибо за подробные разяснения :).


 
Ling ©   (2005-10-01 12:17) [21]

Мдяя..... с++ шаблоны рулят, причём намного выходя за рамки того, ради чего они были придуманны 8))

ХОЧУ ШАБЛОНЫ В DELPHI!!!!


 
Kolan ©   (2005-10-01 12:33) [22]

Ling ©   (01.10.05 12:17) [21]
А что такое шаблоны? Ты не про <Ctrl> + J случано...


 
TUser ©   (2005-10-01 12:44) [23]

Имхо, это все решается объявлением
TNodeClass = class of (TCustomNode);
Пример есть в справке.

> ХОЧУ ШАБЛОНЫ В DELPHI!!!!

Возможно, если отказаться от использования IDE.


 
Игорь Шевченко ©   (2005-10-03 12:01) [24]

TUser ©   (01.10.05 12:44) [23]


> > ХОЧУ ШАБЛОНЫ В DELPHI!!!!
>
> Возможно, если отказаться от использования IDE.


С этого места подробнее - как возможно и чем мешает IDE ?


 
Deka ©   (2005-10-03 15:37) [25]

Где-то я читал статью про шаблоны в Дельфи... Кажись в Королевстве Дельфи. Там у автора все замечательно получилось!



Страницы: 1 вся ветка

Текущий архив: 2005.10.23;
Скачать: CL | DM;

Наверх




Память: 0.55 MB
Время: 0.068 c
6-1120492536
Vriter
2005-07-04 19:55
2005.10.23
Информация о дисках удаленной машины


3-1126712886
terra0
2005-09-14 19:48
2005.10.23
ADO&amp;SQL запрос с параметром


2-1127822325
Vermucht
2005-09-27 15:58
2005.10.23
Строчки как в Object Inspector


3-1126160356
ks
2005-09-08 10:19
2005.10.23
Изменение пароля БД Paradox из приложения


14-1128496222
vidiv
2005-10-05 11:10
2005.10.23
Новый админ на сайте