Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2008.01.06;
Скачать: [xml.tar.bz2];

Вниз

Создание объекта с динамическим классом   Найти похожие ветки 

 
Александр Семак   (2007-12-10 08:28) [0]

Как можно при создании объекта формировать строку названия его класса. Типа такого:
Object1 := Create.<вот тут формируем строку с именем класса>(...)


 
Думкин ©   (2007-12-10 08:30) [1]

Куда формировать?


 
Сергей М. ©   (2007-12-10 08:37) [2]


> := Create.<вот тут


М.б. ты имел ввиду

Object1 := <вот тут.Create(...)

?


 
Григорьев Антон ©   (2007-12-10 08:37) [3]

Все классы, которые нужно таким образом создавать, должны иметь виртуальный конструктор. Дальше заводится тип TMyClassRef = class of TSomeClass (это т.н. ссылка на класс), где TSomeClass - общий предок всех классов, которые нужно создавать таким образом. После этого экземпляр требуемого класса можно создавать с помощью конструкции Obj := X.Create(...), где X - переменная типа TMyClassRef. Этой переменной можно присваивать любые классы типа TSomeClass или его наследников. Если же необходима именно строка с именем, то все классы должны ещё иметь среди предков TPersistent, быть зарегистрированными с помощью процедуры RegisterClass, и тогда ссылку на класс по его имени можно получить через FindClass.


 
oxffff ©   (2007-12-10 08:46) [4]


> Все классы, которые нужно таким образом создавать, должны
> иметь виртуальный конструктор.


Это неправда.


 
Александр Семак   (2007-12-10 08:55) [5]

2 Сергей М. действительно напутал, именно это и имел в виду.


 
Сергей М. ©   (2007-12-10 08:57) [6]


> Александр Семак   (10.12.07 08:55) [5]


тогда см. [3]


 
oxffff ©   (2007-12-10 09:06) [7]


> Если же необходима именно строка с именем, то все классы
> должны ещё иметь среди предков TPersistent, быть зарегистрированными
> с помощью процедуры RegisterClass, и тогда ссылку на класс
> по его имени можно получить через FindClass.


Это тоже не правда.

P.S. никто никому не должен, а это лишь используется component streaming system.


 
Юрий Зотов ©   (2007-12-10 09:22) [8]

> oxffff ©   (10.12.07 09:06) [7]

>> Если же необходима именно строка с именем, то все классы
>> должны ещё иметь среди предков TPersistent, быть зарегистрированными
>> с помощью процедуры RegisterClass, и тогда ссылку на класс
>> по его имени можно получить через FindClass.

> Это тоже не правда.

В приведенной Вами цитате Антон утверждает 3 вещи:
1. Что ссылку на класс по его имени можно получить через FindClass.
2. Что для этого класс должен быть сначала зарегистрирован.
3. И быть потомком TPersistent.

Что же именно из этого неправда?


 
oxffff ©   (2007-12-10 09:39) [9]


> Юрий Зотов ©   (10.12.07 09:22) [8]


Неправда первая.

Для инстанцирования метакласса, класс не обязан (в смысле долженствования) содержать виртуального конструктора.

Неправда вторая.

Для получения ссылки на метакласс по имени не обязательно (в смысле долженствования) использовать component streaming system и быть потомком Tpersistent. Никто не мешает использовать например хэш таблицу.


 
oxffff ©   (2007-12-10 09:51) [10]


> oxffff ©   (10.12.07 09:39) [9]


Использование Tpersistent может быть неоправдано по причине того, что
помимо того, что  есть {$M+} еще и расширение VMT и DMT.
Чем автор возможно вообще не будет пользоваться.
:)


 
oxffff ©   (2007-12-10 09:53) [11]


> oxffff ©   (10.12.07 09:51) [10]


А это увы увеличивает размер EXE.

P.S.

to Юрий Зотов ©

Говорить нужно точно.


 
Юрий Зотов ©   (2007-12-10 09:54) [12]

> oxffff ©   (10.12.07 09:39) [9]

Насчет первого я и не возражал.

Насчет второго - то, что можно использовать собственную регистрацию - это столь же очевидно, сколь и тривиально. Но Антон-то говорил о другом - о поиске через FindClass. И все, что он сказал об этом - правда.


 
oxffff ©   (2007-12-10 10:09) [13]


> Юрий Зотов ©   (10.12.07 09:54) [12]


>Если же необходима именно строка с именем, то все классы должны ещё >иметь среди предков TPersistent, быть зарегистрированными с помощью >процедуры RegisterClass, и тогда ссылку на класс по его имени можно >получить через FindClass.

А это что?

:)

P.S. Учитесь говорить точно и правильно.
Чему и я тоже все еще учусь.


 
Юрий Зотов ©   (2007-12-10 10:19) [14]

> oxffff ©   (10.12.07 10:09) [13]

> А это что?

На мой взгляд, в этих словах Антона все верно. Поэтому и попросил Вас пояснить, что же конкретно в этих словах неточно или неправильно. Но ответа пока нет.

> Чему и я тоже все еще учусь.

Очень хорошо. Тогда в качестве учебного упражнения предложил бы Вам переформулировать слова Антона так, чтобы они звучали точно и правильно. Заодно и мы поучимся - в точном соответствии с Вашими рекомендациями.


 
oxffff ©   (2007-12-10 10:28) [15]


> Юрий Зотов ©   (10.12.07 10:19) [14]
> > oxffff ©   (10.12.07 10:09) [13]
>
> > А это что?
>
> На мой взгляд, в этих словах Антона все верно. Поэтому и
> попросил Вас пояснить, что же конкретно в этих словах неточно
> или неправильно. Но ответа пока нет.


Ответ был. Я его выделил жирным.

>Как можно при создании объекта формировать строку названия его класса.

Судя по словам автору необходимо получить строку класса в исходном тексте.

Однако, если мы включим телепатор.
То возможно мы может угадать, чего хотел автор.
Поэтому корректируя слова

Григорьев Антон ©

я бы заменил слово "должен" на "мог бы". И убрал бы информацию о виртуальном конструкторе.


 
Григорьев Антон ©   (2007-12-10 10:37) [16]

Виртуальный конструктор быть должен. Просто потому, что при создании класса через ссылку нужно, чтобы вызывался конструктор того класса, экземпляр которого создаётся, а не общего предка. Конечно, объект создаваться будет и без вирутального конструктора, но в большинстве случаев это будет означать, что он создаётся не своим конструктором, а конструктором предка, т.е. часть полей могут оказаться не инициализированными. И использование такого недоинициализированного объекта - потенциальный источник ошибок. Слово "должен" здесь следует понимать не как "без этого работать не будет", а как "следует делать, потому что иначе легко нарваться на ошибку". Точно так же, как, например, в фразе "поля класса должны иметь видимость private, а для доступа к ним извне должны быть объявлены соответствующие свойства". Здесь идёт речь не о невозможности сделать по-другому, а о грамотном стиле.


 
Юрий Зотов ©   (2007-12-10 10:38) [17]

> автору

Вот пример решения Вашей задачи с использованием собственной регистрации классов:

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.


 
oxffff ©   (2007-12-10 10:49) [18]


> Григорьев Антон ©   (10.12.07 10:37) [16]


Для корректной инициализации экземляра без параметров, можно использовать перекрытие NewInstance и Afterconstruction без использования виртуального конструктора.


> Юрий Зотов ©   (10.12.07 10:38) [17]


Respect.


 
Юрий Зотов ©   (2007-12-10 10:50) [19]

> Григорьев Антон ©   (10.12.07 10:37) [16]

> объект создаваться будет и без вирутального конструктора, но в
> большинстве случаев это будет означать, что он создаётся не своим
> конструктором, а конструктором предка, т.е. часть полей могут оказаться
> не инициализированными.

Кстати, да.

> И использование такого недоинициализированного объекта -
> потенциальный источник ошибок.

Причем ошибок, которые для начинающих еще и трудноуловимы.


 
Юрий Зотов ©   (2007-12-10 11:08) [20]

> oxffff ©   (10.12.07 10:49) [18]

> Для корректной инициализации экземляра без параметров, можно
> использовать перекрытие NewInstance...

Коллега, ну елки-палки, разве такие вещи - для начинающих? Надо же все таки учитывать реалии, а то ведь так можно предложить и хук на _ClassCreate поставить... тоже ведь решение...
:о)


 
oxffff ©   (2007-12-10 11:19) [21]


> хук на _ClassCreate поставить


А как если не секрет?


 
Юрий Зотов ©   (2007-12-10 11:28) [22]

> oxffff ©   (10.12.07 11:19) [21]

Дык... к примеру, так же, как на API-вызовы хуки ставят - подменой адресов.


 
oxffff ©   (2007-12-10 12:44) [23]


> Юрий Зотов ©   (10.12.07 11:28) [22]


Дык, может пример в студию?

P.S. _ClassCreate calling is binded at compile time.


 
DiamondShark ©   (2007-12-10 14:04) [24]


> Юрий Зотов ©   (10.12.07 10:50) [19]
> > Григорьев Антон ©   (10.12.07 10:37) [16]
>
> > объект создаваться будет и без вирутального конструктора,
>  но в
> > большинстве случаев это будет означать, что он создаётся
> не своим
> > конструктором, а конструктором предка, т.е. часть полей
> могут оказаться
> > не инициализированными.
>
> Кстати, да.

Кстати, нет.
Если экземпляр создаётся вызовом статического конструктора, это будет просто экземпляр базового типа. Никакой "части полей" там вообще не будет.


 
Григорьев Антон ©   (2007-12-10 14:50) [25]


> 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 не получило ожидаемое значение.


 
Юрий Зотов ©   (2007-12-10 15:13) [26]

> oxffff ©   (10.12.07 12:44) [23]

Даже и на полсекунды напрягаться не стану.

Скажите, а Вы всегда все понимаете буквально? Или в обычной жизни с этим дело обстоит все же получше?

> DiamondShark ©   (10.12.07 14:04) [24]

Таким образом, в [25] утверждение "это будет просто экземпляр базового типа" опровергнуто.

А если вывести еще и InstanceSize, то увидим, что поле C2 хотя и не проинициализировано (что и должно было быть), но присутствует вполне успешно. То есть, утверждение "никакой "части полей" там вообще не будет" опровергнуто тоже.


 
DiamondShark ©   (2007-12-10 15:22) [27]

Забыл про виртуальный TObject.NewInstance.


 
oxffff ©   (2007-12-10 15:23) [28]


> Юрий Зотов ©   (10.12.07 15:13) [26]
> > oxffff ©   (10.12.07 12:44) [23]
>
> Даже и на полсекунды напрягаться не стану.
>
> Скажите, а Вы всегда все понимаете буквально? Или в обычной
> жизни с этим дело обстоит все же получше?


:). По разному. :)


 
oxffff ©   (2007-12-10 15:24) [29]


> DiamondShark ©   (10.12.07 15:22) [27]


Это то здесь причем?


 
DiamondShark ©   (2007-12-10 15:29) [30]


> oxffff ©   (10.12.07 15:24) [29]
>
> > DiamondShark ©   (10.12.07 15:22) [27]
>
>
> Это то здесь причем?

При том, что экземпляр объекта размещается на куче вызовом классовой виртуальной функции TObject.NewInstance
Т.е. размер объекта всегда будет правильный. И даже нулями правильно заинициализируется.


 
oxffff ©   (2007-12-10 15:32) [31]


> DiamondShark ©   (10.12.07 15:29) [30]


Ответь почему именно за это отвечает его виртуальность.


 
oxffff ©   (2007-12-10 15:34) [32]


> DiamondShark ©   (10.12.07 15:29) [30]


Если бы NewInstance был невиртуальный, то было бы ровным счетом тоже самое.
Ути-пути.


 
DiamondShark ©   (2007-12-10 15:41) [33]


> oxffff ©   (10.12.07 15:32) [31]
>
> > DiamondShark ©   (10.12.07 15:29) [30]
>
>
> Ответь почему именно за это отвечает его виртуальность.

С превеликим удовольствием, как только ты мне покажешь, где я это утврждал.


 
oxffff ©   (2007-12-10 15:51) [34]

DiamondShark ©   (10.12.07 15:22) [27] z
> DiamondShark ©   (10.12.07 15:41) [33]


У тебя что склероз?

DiamondShark ©   (10.12.07 15:22) [27]

Только его заслуга не в том, что он виртуальный, а в том, что он классовый.
Так что увы. УТИ-ПУТИ.


 
DiamondShark ©   (2007-12-10 15:54) [35]


> oxffff ©   (10.12.07 15:34) [32]
>
> > DiamondShark ©   (10.12.07 15:29) [30]
>
>
> Если бы NewInstance был невиртуальный, то было бы ровным
> счетом тоже самое.

Ты считаешь, что правильный размер объекта -- это тот, что записан в поле vmtInstanceSize? Ути-пути.
NewInstance Может быть перекрыт и, вообще говоря, разработчик наследников имеет полное право размещать экземпляры как ему подскажет больное воображение.

Это к вопросу "при чём тут виртуальность".


 
DiamondShark ©   (2007-12-10 15:55) [36]


> oxffff ©   (10.12.07 15:51) [34]
> DiamondShark ©   (10.12.07 15:22) [27] z
> > DiamondShark ©   (10.12.07 15:41) [33]
>
>
> У тебя что склероз?

А у тебя косоглазие? Где ты там вычитал, про " именно за это отвечает его виртуальность"?


 
oxffff ©   (2007-12-10 16:04) [37]


> DiamondShark ©   (10.12.07 15:54) [35]


А ты наверно хочешь сказать vmtInstanceSize может быть даже меньше чем необходимому экземпляру? Ути-пути.

Далее по тексту.
Назначение NewInstance и freeInstance в том, чтобы изменять способ размещения объектов. Однако перекрытие поведения в том числе и dyna расширение instance"a является следствием, а не целью.

НО!!!

Вопрос был в том, что в [27] ты с полной уверенностью утверждал, что такое поведение обусловлено именно виртуальностью NewInstance.

А судя по DiamondShark ©   (10.12.07 14:04) [24], где ты не знал реализацию инстанцирования.
И два часа изучив _classCreate и NewInstance пытаешься загладить отсутствие знаний.

Косоглазие. Не у меня, а тебя. Перечитай [27].


 
oxffff ©   (2007-12-10 16:08) [38]


> DiamondShark ©   (10.12.07 15:55) [36]



> DiamondShark ©   (10.12.07 15:22) [27]
> Забыл про виртуальный TObject.NewInstance.


Забыл, да еще и не знал.

;)


 
DiamondShark ©   (2007-12-10 16:11) [39]


> oxffff ©   (10.12.07 16:04) [37]


> Вопрос был в том, что в [27] ты с полной уверенностью утверждал,
>  что такое поведение обусловлено именно виртуальностью NewInstance.

Да что ты говоришь? Так прямо и написано: "именно виртуальностью"?

К окулисту, срочно.


 
DiamondShark ©   (2007-12-10 16:13) [40]


> oxffff ©   (10.12.07 16:08) [38]

Ну точно, что-то с глазами. Жирный шрифт мерещится.

Лечись, телепат.



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

Форум: "Начинающим";
Текущий архив: 2008.01.06;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.57 MB
Время: 0.005 c
2-1197293417
kyn66
2007-12-10 16:30
2008.01.06
Рисование на канве Image


15-1196622484
shlst
2007-12-02 22:08
2008.01.06
Ваши состояния :)


15-1196689767
alsov
2007-12-03 16:49
2008.01.06
событие виндовс на email


11-1182345030
nikfel
2007-06-20 17:10
2008.01.06
Как изменить цвет линии.


8-1170839529
ZMRaven
2007-02-07 12:12
2008.01.06
dspack





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский