![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Создание объекта с динамическим классом [D7, XP]
Александр Семак © (2007-12-10 08:28:00)Как можно при создании объекта формировать строку названия его класса. Типа такого:
Object1 := Create.<вот тут формируем строку с именем класса>(...)
Юрий Зотов (2007-12-10 15:13:00) [21]> oxffff © (10.12.07 12:44) [23]
Даже и на полсекунды напрягаться не стану.
Скажите, а Вы всегда все понимаете буквально? Или в обычной жизни с этим дело обстоит все же получше?
> DiamondShark © (10.12.07 14:04) [24]
Таким образом, в [25] утверждение "это будет просто экземпляр базового типа" опровергнуто.
А если вывести еще и InstanceSize, то увидим, что поле C2 хотя и не проинициализировано (что и должно было быть), но присутствует вполне успешно. То есть, утверждение "никакой "части полей" там вообще не будет" опровергнуто тоже.
Григорьев Антон (2007-12-10 14:50:00) [22]
> DiamondShark © (10.12.07 14:04) [24]
> Кстати, нет.
> Если экземпляр создаётся вызовом статического конструктора,
> это будет просто экземпляр базового типа. Никакой "части
> полей" там вообще не будет.
Если через классовую ссылку - да. Вот код
type
TClass1 = class
private
C1: Integer;
public
constructor Create;
end;
TClass2 = class(TClass1)
private
C2: Integer;
public
constructor Create;
end;
TClassRef = class of TClass1;
constructor TClass1.Create;
begin
inherited;
C1 := 10;
end;
constructor TClass2.Create;
begin
inherited;
C2 := 20;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Obj: TClass1;
Ref: TClassRef;
begin
Ref := TClass2;
Obj := Ref.Create;
ShowMessage('Name=' + Obj.ClassName +
' C1=' + IntToStr(Obj.C1) +
' C2=' + IntToStr((Obj as TClass2).C2));
end;
Выводит строку "Name=TClass2, C1=10, C2=0", т.е. создался экземпляр TClass2, но инициализировался конструктором TClass1.Create, а TClass2.Create не был вызван, и поле C2 не получило ожидаемое значение.
DiamondShark (2007-12-10 14:04:00) [23]
> Юрий Зотов © (10.12.07 10:50) [19]
> > Григорьев Антон © (10.12.07 10:37) [16]
>
> > объект создаваться будет и без вирутального конструктора,
> но в
> > большинстве случаев это будет означать, что он создаётся
> не своим
> > конструктором, а конструктором предка, т.е. часть полей
> могут оказаться
> > не инициализированными.
>
> Кстати, да.
Кстати, нет.
Если экземпляр создаётся вызовом статического конструктора, это будет просто экземпляр базового типа. Никакой "части полей" там вообще не будет.
oxffff (2007-12-10 12:44:00) [24]
> Юрий Зотов © (10.12.07 11:28) [22]
Дык, может пример в студию?
P.S. _ClassCreate calling is binded at compile time.
Юрий Зотов (2007-12-10 11:28:00) [25]> oxffff © (10.12.07 11:19) [21]
Дык... к примеру, так же, как на API-вызовы хуки ставят - подменой адресов.
oxffff (2007-12-10 11:19:00) [26]
> хук на _ClassCreate поставить
А как если не секрет?
Юрий Зотов (2007-12-10 11:08:00) [27]> oxffff © (10.12.07 10:49) [18]
> Для корректной инициализации экземляра без параметров, можно
> использовать перекрытие NewInstance...
Коллега, ну елки-палки, разве такие вещи - для начинающих? Надо же все таки учитывать реалии, а то ведь так можно предложить и хук на _ClassCreate поставить... тоже ведь решение...
:о)
Юрий Зотов (2007-12-10 10:50:00) [28]> Григорьев Антон © (10.12.07 10:37) [16]
> объект создаваться будет и без вирутального конструктора, но в
> большинстве случаев это будет означать, что он создаётся не своим
> конструктором, а конструктором предка, т.е. часть полей могут оказаться
> не инициализированными.
Кстати, да.
> И использование такого недоинициализированного объекта -
> потенциальный источник ошибок.
Причем ошибок, которые для начинающих еще и трудноуловимы.
oxffff (2007-12-10 10:49:00) [29]
> Григорьев Антон © (10.12.07 10:37) [16]
Для корректной инициализации экземляра без параметров, можно использовать перекрытие NewInstance и Afterconstruction без использования виртуального конструктора.
> Юрий Зотов © (10.12.07 10:38) [17]
Respect.
Юрий Зотов (2007-12-10 10:38:00) [30]> автору
Вот пример решения Вашей задачи с использованием собственной регистрации классов:
type
TMyClass1 = class
end;
TMyClass = class of TMyClass1;
TMyClass2 = class(TMyClass1)
end;
const
MyClasses: array[0..1] of TMyClass = (TMyClass1, TMyClass2);
MyClassNames: array[0..1] of string = ('TMyClass1', 'TMyClass2');
function FindMyClass(MyClassName: string): TMyClass;
var
i: integer;
begin
for i := 0 to 1 do
if AnsiSameText(MyClassName, MyClassNames[i]) then
begin
Result := MyClasses[i];
Exit
end;
Result := nil
end;
procedure TForm1.FormCreate(Sender: TObject);
var
C: TMyClass;
begin
C := FindMyClass('TMyClass2');
with C.Create do
try
Caption := ClassName
finally
Free
end
end;
Если же Ваш базовый класс (в примере это TMyClass1) наследуется от TPersistent (не обязательно напрямую), то можно использовать штатную регистрацию:
type
TMyClass1 = class(...)
end;
TMyClass2 = class(TMyClass1)
end;
procedure TForm1.FormCreate(Sender: TObject);
var
C: TPersistentClass;
begin
RegisterClasses([TMyClass1, TMyClass2]);
C := FindClass('TMyClass1');
with C.Create do
try
Caption := ClassName
finally
Free
end
end;
В таких случаях вызов RegisterClasses([TMyClass1, TMyClass2]) обычно производится где-то в секции initialization. Важно лишь то, чтобы этот вызов был сделан ДО вызова FindClass.
Григорьев Антон (2007-12-10 10:37:00) [31]Виртуальный конструктор быть должен. Просто потому, что при создании класса через ссылку нужно, чтобы вызывался конструктор того класса, экземпляр которого создаётся, а не общего предка. Конечно, объект создаваться будет и без вирутального конструктора, но в большинстве случаев это будет означать, что он создаётся не своим конструктором, а конструктором предка, т.е. часть полей могут оказаться не инициализированными. И использование такого недоинициализированного объекта - потенциальный источник ошибок. Слово "должен" здесь следует понимать не как "без этого работать не будет", а как "следует делать, потому что иначе легко нарваться на ошибку". Точно так же, как, например, в фразе "поля класса должны иметь видимость private, а для доступа к ним извне должны быть объявлены соответствующие свойства". Здесь идёт речь не о невозможности сделать по-другому, а о грамотном стиле.
oxffff (2007-12-10 10:28:00) [32]
> Юрий Зотов © (10.12.07 10:19) [14]
> > oxffff © (10.12.07 10:09) [13]
>
> > А это что?
>
> На мой взгляд, в этих словах Антона все верно. Поэтому и
> попросил Вас пояснить, что же конкретно в этих словах неточно
> или неправильно. Но ответа пока нет.
Ответ был. Я его выделил жирным.
>Как можно при создании объекта формировать строку названия его класса.
Судя по словам автору необходимо получить строку класса в исходном тексте.
Однако, если мы включим телепатор.
То возможно мы может угадать, чего хотел автор.
Поэтому корректируя слова
Григорьев Антон ©
я бы заменил слово "должен" на "мог бы". И убрал бы информацию о виртуальном конструкторе.
Юрий Зотов (2007-12-10 10:19:00) [33]> oxffff © (10.12.07 10:09) [13]
> А это что?
На мой взгляд, в этихсловах Антона все верно. Поэтому и попросил Вас пояснить, что же конкретно в этих словах неточно или неправильно. Но ответа пока нет.
> Чему и я тоже все еще учусь.
Очень хорошо. Тогда в качестве учебного упражнения предложил бы Вам переформулировать слова Антона так, чтобы они звучали точно и правильно. Заодно и мы поучимся - в точном соответствии с Вашими рекомендациями.
oxffff (2007-12-10 10:09:00) [34]
> Юрий Зотов © (10.12.07 09:54) [12]
>Если же необходима именно строка с именем, то все классы должныещё >иметь среди предков TPersistent, быть зарегистрированными с помощью >процедуры RegisterClass, и тогда ссылку на класс по его имени можно >получить через FindClass.
А это что?
:)
P.S. Учитесь говорить точно и правильно.
Чему и я тоже все еще учусь.
Юрий Зотов (2007-12-10 09:54:00) [35]> oxffff © (10.12.07 09:39) [9]
Насчет первого я и не возражал.
Насчет второго - то, что можно использовать собственную регистрацию - это столь же очевидно, сколь и тривиально. Но Антон-то говорил о другом- о поиске через FindClass. И все, что он сказал об этом- правда.
oxffff (2007-12-10 09:53:00) [36]
> oxffff © (10.12.07 09:51) [10]
А это увы увеличивает размер EXE.
P.S.
to Юрий Зотов ©
Говорить нужно точно.
oxffff (2007-12-10 09:51:00) [37]
> oxffff © (10.12.07 09:39) [9]
Использование Tpersistent может быть неоправдано по причине того, что
помимо того, что есть {$M+} еще и расширение VMT и DMT.
Чем автор возможно вообще не будет пользоваться.
:)
oxffff (2007-12-10 09:39:00) [38]
> Юрий Зотов © (10.12.07 09:22) [8]
Неправда первая.
Для инстанцирования метакласса, класс не обязан (в смысле долженствования) содержать виртуального конструктора.
Неправда вторая.
Для получения ссылки на метакласс по имени не обязательно (в смысле долженствования) использовать component streaming system и быть потомком Tpersistent. Никто не мешает использовать например хэш таблицу.
Юрий Зотов (2007-12-10 09:22:00) [39]> oxffff © (10.12.07 09:06) [7]
>> Если же необходима именно строка с именем, то все классы
>> должны ещё иметь среди предков TPersistent, быть зарегистрированными
>> с помощью процедуры RegisterClass, и тогда ссылку на класс
>> по его имени можно получить через FindClass.
> Это тоже не правда.
В приведенной Вами цитате Антон утверждает 3 вещи:
1. Что ссылку на класс по его имени можно получить через FindClass.
2. Что для этого класс должен быть сначала зарегистрирован.
3. И быть потомком TPersistent.
Что же именно из этого неправда?
oxffff (2007-12-10 09:06:00) [40]
> Если же необходима именно строка с именем, то все классы
> должны ещё иметь среди предков TPersistent, быть зарегистрированными
> с помощью процедуры RegisterClass, и тогда ссылку на класс
> по его имени можно получить через FindClass.
Это тоже не правда.
P.S. никто никому не должен, а это лишь используется component streaming system.