Форум: "Основная";
Текущий архив: 2005.01.02;
Скачать: [xml.tar.bz2];
ВнизКак создать объект по имени его класса Найти похожие ветки
← →
Чайник © (2004-12-15 18:43) [0]У меня создан базовый класс типа TBlock = class(TComponent), и ряд производных от него классов вида TBlock1 = class(TBlock), TBlock2 и т.д. Как в программе создать объект конкретного класса, если я знаю его имя (имя сидит в строке вроде NewBlock = "TBlock1" : string)?
← →
Суслик © (2004-12-15 18:47) [1]изучай registerclass + findclass
← →
Чайник © (2004-12-15 18:57) [2]Изучаю.
Каждый модуль с описанием класса имеет секцию
initialization
RegisterClass(TBlock1);
Далее, в программе объявлен тип:
type TBlockClass = class of TBlock;
В процедуре добавления блока есть
var tmpBlockClass : TBlockClass;
tmpBlock : TBlock;
...
tmpBlockClass := TBlockClass(FindClass(newBlock));
tmpBlock := tmpBlockClass.Create(Self);
При запуске имею: Class TBlock1 not found. Почему?
← →
jack128 © (2004-12-15 19:11) [3]а чему равно newBlock на момент вызова??
Когда вызывается процедура добавления? Случайно не в секции ининциализации?
а если так tmpBlockClass := TBlockClass(FindClass("TBlock1")); то работает??
← →
Чайник © (2004-12-15 19:17) [4]>а чему равно newBlock на момент вызова??
newBlock содержит имя класса;
>Когда вызывается процедура добавления? Случайно не в секции ининциализации? - нет, из процедуры.
>а если так tmpBlockClass := TBlockClass(FindClass("TBlock1")); то работает??
нет, и так не работает.
← →
jack128 © (2004-12-15 19:20) [5]хм. Больше мыслкй нет. Отладчиком пройдись, что еще можно посоветовать...
← →
Чайник © (2004-12-15 19:34) [6]Опа!
У меня секция initialization не выполняется! Что за новости???
← →
Sergey_Masloff (2004-12-15 19:53) [7]Чайник © (15.12.04 19:34) [6]
>У меня секция initialization не выполняется! Что за новости???
Значит этого модуля в USES нигде нет. Проверь?
← →
Чайник © (2004-12-15 20:31) [8]Вы будете смеяться, но теперь не выполняется секция finalization.
Чтобы это значило?
Кстати, а она всегда должна выполняться?
← →
Sergey_Masloff (2004-12-15 20:46) [9]Вобщем, ничего не понятно. Тебе нужно что-то типа этого?
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Edit1: TEdit;
btCreate: TButton;
btClose: TButton;
procedure btCloseClick(Sender: TObject);
procedure btCreateClick(Sender: TObject);
end;
var
Form1: TForm1;
implementation
uses Unit2;
{$R *.dfm}
procedure TForm1.btCloseClick(Sender: TObject);
begin
Close();
end;
procedure TForm1.btCreateClick(Sender: TObject);
var
cls : TComponentClass;
ptr : Pointer;
begin
cls := TComponentClass(GetClass(Edit1.Text));
if Assigned(cls) then
try
ptr := cls.Create(Application);
ShowMessage(TBlock1(ptr).GetName);
finally
TObject(ptr).Free();
end else
ShowMessage("Класс не найден");end;
end.
//////// Unit2
unit Unit2;
interface
uses Classes;
type
TBlock = class(TComponent);
TBlock1 = class(TBlock)
public
function GetName : String;
end;
implementation
{ TBlock1 }
function TBlock1.GetName: String;
begin
Result := "TBlok1 at your service!";
end;
initialization
RegisterClass(TBlock1);
end.
Форма с 2 кнопками и едитом. В едит вводишь TBlock1 получаешь строку возвращаемую TBlock1.GetName. Тебе это нужно
← →
Чайник © (2004-12-15 22:27) [10]Прошу прощения, вынужденно отвлекся от занимательной дискуссии.
>Sergey_Masloff
У меня объявлен массив Blocks : array of TBlock; , так вот, мне нужно, чтобы вызывался конструктор Create именно конкретного производного класса (TBlock1 или TBlock2 или TBlockN), а не родительского TBlock.
Я пробовал по Вашему совету:
procedure TFEditor.btnBlockAddClick(Sender: TObject);
var tmpBlockClass : TComponentClass;
tmpBlock : Pointer;
...
tmpBlockClass := TComponentClass(GetClass(newBlock));
tmpBlock := tmpBlockClass.Create(Self);
Выполняется Create родительского класса, а не того, чье имя сидит в newBlock
← →
Чайник © (2004-12-15 22:36) [11]Ответ на собственный вопрос:
>Вы будете смеяться, но теперь не выполняется секция finalization.
>Чтобы это значило?
>Кстати, а она всегда должна выполняться?
У меня для отладки туда воткнуто ShowMessage("finalization");
Так вот ShowMessage отображается, только тотчас исчезает.
← →
vuk © (2004-12-15 22:46) [12]to Чайник © (15.12.04 22:27) [10]:
>так вот, мне нужно, чтобы вызывался конструктор Create именно
>конкретного производного класса (TBlock1 или TBlock2 или
>TBlockN), а не родительского TBlock.
Конструктор сделайте виртуальным. Как, например, это у TComponent сделано.
← →
Sergey_Masloff (2004-12-15 22:48) [13]Перепишем Unit2
unit Unit2;
interface
uses Classes;
type
TBlock = class(TComponent)
protected
fData : String;
public
function GetName : String;
end;
TBlock1 = class(TBlock)
public
constructor Create(AOwner : TComponent); reintroduce; override;
end;
TBlock2 = class(TBlock)
public
constructor Create(AOwner : TComponent); reintroduce; override;
end;
implementation
{ TBlock1 }
{ TBlock }
function TBlock.GetName: String;
begin
result := fData;
end;
{ TBlock1 }
constructor TBlock1.Create(AOwner: TComponent);
begin
inherited;
fData := "Block1 at service";
end;
{ TBlock2 }
constructor TBlock2.Create(AOwner: TComponent);
begin
inherited;
fData := "Block2 at service";
end;
initialization
RegisterClasses([TBlock1, TBlock2]);
end.
При вводе имен разных блоков выдаются разные сообщения - т.е. конструкторы работают. Там нигде override не забыли в иерархии?
← →
Zacho © (2004-12-15 22:48) [14]Чайник © (15.12.04 22:27) [10]
Приведи свой код полностью. А то есть у меня некоторые подозрения, да телепатировать лень :)
← →
Sergey_Masloff (2004-12-15 22:50) [15]vuk © (15.12.04 22:46) [12]
>Конструктор сделайте виртуальным. Как, например, это у >TComponent сделано.
Это все потомки TComponent наверное где-то виртуальный конструктор заместили статическим. Вобщем код надо смотреть подробнее.
← →
Чайник © (2004-12-15 22:51) [16]Ура! Заработало! (с) Матроскин.
Работающий вариант:
procedure TFEditor.btnBlockAddClick(Sender: TObject);
var tmpBlockClass : TBlockClass;
tmpBlockClassName : String;
...
tmpBlockClassName := ListNamesBlock[tmpNo].ClassName;
tmpBlockClass := TBlockClass(FindClass(tmpBlockClassName));
BlocksCount := BlocksCount + 1;
SetLength(Blocks, BlocksCount);
Blocks[BlocksCount-1] := tmpBlockClass.Create(Self);
Blocks[BlocksCount-1].Caption := и т.д.
← →
vuk © (2004-12-15 22:53) [17]to Sergey_Masloff (15.12.04 22:50) [15]:
>Это все потомки TComponent наверное где-то виртуальный
>конструктор заместили статическим.
Ну тогда просто override дописать. Сути это не меняет. Либо виртуальный конструктор отсутствует либо определен новый с другой сигнатурой. Другим путем такого эффекта не добиться. А что там на самом деле происходит - фиг его знает. Кода нет, а телепаты в отпуске.
← →
Чайник © (2004-12-15 22:53) [18]Кстати, а оно обязательно надо:
finalization
UnRegisterClass(TBlockCylinder2Dsimm);
← →
Sergey_Masloff (2004-12-15 22:59) [19]Чайник © (15.12.04 22:53) [18]
>Кстати, а оно обязательно надо:
>finalization
> UnRegisterClass(TBlockCylinder2Dsimm);
Не надо. Это можно сделать в коде программы для высвобождения ресурсов но не в финализации - все равно все высвободится автоматически.
← →
Чайник © (2004-12-15 23:09) [20]> Sergey_Masloff (15.12.04 22:59) [19]
Спасибо
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2005.01.02;
Скачать: [xml.tar.bz2];
Память: 0.5 MB
Время: 0.036 c