Коллекция классов - подскажите плз, что не так

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Коллекция классов - подскажите плз, что не так

Сообщение tria » 15.06.2007 16:36:16

Есть следующий код (упрощенно):
Код: Выделить всё
TBaseClass=Class
Constructor Create(); virtual;
...
TBaseClass1=Class(TBaseClass)
Constructor Create(); override;
....
TBaseClasses = class of TBaseClass;

Procedure Do(cl:TBaseClasses);
var b:TBaseClass;
begin
  b:=Pointer(cl.Create());
end;


При вызове процедуры:
Do(TBaseClasses1);
вызывается конструктор TBaseClasses а не TBaseClasses1.
Что я делаю не так? Или как надо сделать, чтобы в процедуре Do() вызывался Constructor переданного класса?
tria
постоялец
 
Сообщения: 401
Зарегистрирован: 03.04.2006 11:24:10

Сообщение shade » 15.06.2007 16:41:44

Конструктор нужно сделать вируальным
Код: Выделить всё
constructor TBaseClass.Create; virtual;
...
constructor TChildClass.Create; override;
...
Аватара пользователя
shade
энтузиаст
 
Сообщения: 879
Зарегистрирован: 21.02.2006 20:15:48
Откуда: http://shamangrad.net/

Сообщение tria » 15.06.2007 16:43:40

так он и есть виртуальный
tria
постоялец
 
Сообщения: 401
Зарегистрирован: 03.04.2006 11:24:10

Сообщение tria » 15.06.2007 16:49:35

Нашел разницу между случаем, когда работает. Перепишу:
Код: Выделить всё
TBaseClass=Class
Constructor Create(); virtual;
...

TBaseClass1=Class(TBaseClass)
Constructor Create(); override;
....

TBaseClass2=Class(TBaseClass)
Constructor Create(); overload; override;
Constructor Create(p:TAnyClass); overload;
....

TBaseClasses = class of TBaseClass;

Procedure Do(cl:TBaseClasses);
var b:TBaseClass;
begin
  b:=Pointer(cl.Create());
end;

Так вот:
Do(TBaseClasses1); - вызывается конструктор TBaseClasses1
Do(TBaseClasses2); - вызывается конструктор TBaseClasses
Выходит, проблема в overload. Как ее обойти?
tria
постоялец
 
Сообщения: 401
Зарегистрирован: 03.04.2006 11:24:10

Сообщение shade » 15.06.2007 16:52:28

Код: Выделить всё
program test_virt_constr;

{$mode objfpc}

uses Classes;

type
  TBaseClass = class
    constructor Create; virtual;
    destructor Destroy; override;
  end;
 
  TBaseClassItem = class of TBaseClass;
 
  TChildClass = class (TBaseClass)
    constructor Create; override;
    destructor Destroy; override;
  end;

constructor TBaseClass.Create;
begin
  inherited Create;
  writeln('TBaseClass.Create');
end;

destructor TBaseClass.Destroy;
begin
  writeln('TBaseClass.Destroy');
  inherited Destroy;
end;

constructor TChildClass.Create;
begin
  inherited Create;
  writeln('TChildClass.Create');
end;

destructor TChildClass.Destroy;
begin
  writeln('TChildClass.Destroy');
  inherited Destroy;
end;

var
  List: TList;
  ClassItem: TBaseClassItem;
  obj: TBaseClass;
begin
  List := TList.Create;
  ClassItem := TChildClass;
  List.Add(ClassItem);
  obj := TBaseClassItem(List[0]).Create;
  obj.Free;
end.

Ожидаемый вывод:
Код: Выделить всё
TBaseClass.Create
TChildClass.Create
TChildClass.Destroy
TBaseClass.Destroy

TBaseClass.Create и TBaseClass.Destroy вызваются, т.к. в моем примере вызыватся метод предка через inherited Create / inherited Destroy, если их убрать то будет просто
Код: Выделить всё
TChildClass.Create
TChildClass.Destroy
Аватара пользователя
shade
энтузиаст
 
Сообщения: 879
Зарегистрирован: 21.02.2006 20:15:48
Откуда: http://shamangrad.net/

Сообщение tria » 15.06.2007 17:01:54

> shade
Извини, что заставил сделать лишнюю работу. Идея о overload мне пришла в голову позже :(
tria
постоялец
 
Сообщения: 401
Зарегистрирован: 03.04.2006 11:24:10

Сообщение shade » 15.06.2007 17:02:30

С overload тоже работает:
Код: Выделить всё
program test_virt_constr;

{$mode objfpc}

uses Classes;

type
  TBaseClass = class
    constructor Create; virtual; overload;
    destructor Destroy; override;
  end;
 
  TBaseClassItem = class of TBaseClass;
 
  TChildClass = class (TBaseClass)
    constructor Create; override;
    constructor Create(const msg: string);
    destructor Destroy; override;
  end;

constructor TBaseClass.Create;
begin
  inherited Create;
  writeln('TBaseClass.Create');
end;

destructor TBaseClass.Destroy;
begin
  writeln('TBaseClass.Destroy');
  inherited Destroy;
end;

constructor TChildClass.Create;
begin
  inherited Create;
  writeln('TChildClass.Create');
end;

constructor TChildClass.Create(const msg: string);
begin
  inherited Create;
  writeln('TChildClass.Create(''', msg, ''')');
end;

destructor TChildClass.Destroy;
begin
  writeln('TChildClass.Destroy');
  inherited Destroy;
end;

function create_base_class(cl: TBaseClassItem): TBaseClass;
begin
  Result := cl.Create;
end;

var
  obj: TBaseClass;
begin
  obj := create_base_class(TChildClass);
  obj.Free;
end.
Аватара пользователя
shade
энтузиаст
 
Сообщения: 879
Зарегистрирован: 21.02.2006 20:15:48
Откуда: http://shamangrad.net/

Сообщение shade » 15.06.2007 17:13:08

Чтобы не искать трудно обнаружимые ошибки, просто не давай им шанса появиться, а поэтому не используй похожие имена типа TBase1, TBase2, TBases,
используй более различные, например:
TFoo = class;
TBar = class (TFoo);
TBanana = class (TBar);
TFooClass = class of TFoo;
:wink:
Аватара пользователя
shade
энтузиаст
 
Сообщения: 879
Зарегистрирован: 21.02.2006 20:15:48
Откуда: http://shamangrad.net/

Сообщение tria » 15.06.2007 17:40:17

На самом деле у меня все гороаздо сложнее и реальные имена классов другие, пример я привел упрощенный, дабы показать смысл проблемы.
Ваш код у меня дал тот же результат.
Единственно, у меня в программе используется {$MODE Delphi}
для этого случая пришлось добавить overload:
Код: Выделить всё
  TChildClass = class (TBaseClass)
    constructor Create; override; overload;
    constructor Create(const msg: string); overload;
    destructor Destroy; override;
  end;


В общем, "будем искать" :(
tria
постоялец
 
Сообщения: 401
Зарегистрирован: 03.04.2006 11:24:10


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 44

Рейтинг@Mail.ru