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

Вниз

Виртуальный конструктор   Найти похожие ветки 

 
Genri   (2003-09-04 13:19) [0]

Всем доброго времени суток
Объясните новичку, плз, что такое виртуальный конструктор и как им пользоваться


 
Vlad   (2003-09-04 13:20) [1]

Это виртуальный молоток, виртуальные пасатижи итд.


 
Skier   (2003-09-04 13:21) [2]


> Объясните новичку

новичку не следует начинать с бомбардировки форума...


 
KSergey   (2003-09-04 13:27) [3]

Конструктор объекта не может быть виртуальным.
Это не имеет смысла.


 
MBo   (2003-09-04 13:30) [4]

>KSergey
ошибаешься.
TComponent.Create


 
Calm   (2003-09-04 13:35) [5]


> Это не имеет смысла

Буду знать. А то все использую и использую...


 
PVOzerski   (2003-09-04 13:42) [6]

Один из примеров полезности виртуальных конструкторов (может и единственный - по крайней мере, я осознал смысл их именно в этой ситуации) - это использование их в сочетании с метаклассами.

Например,
var
MetaClass:tClass;
Obj:tObject;
begin
MetaClass:=... Некий класс с виртуальным Create, скажем, переданный как параметр.
Obj:=MetaClass.Create;
Теперь мы можем в рантайме решать, объект какого класса создавать, и при этом вызовется правильный конструктор.


 
Palladin   (2003-09-04 13:42) [7]

Constructor Create; virtual;
Пользоватся нужно не им, а предоставленной возможностью.
Обычно виртуальные конструкторы используются вместе с определением class of;

То есть создается некое семейство классов.
TMyBase=class
...
constructor Create; virtual;
end;

TMyBaseClass=class of TMyBase;

TMyCoolClass1=class(TMyBase)
...
constructor Create; override;
end;

TMyCoolClass2=class(TMyBase);
...
constructor Create; override;
end;

TMyVeryCoolClass1=class(TMyCoolClass1);
...
constructor Create; override;
end;

function CreateClass(var AObject:TMyBase;AClass:TMyBaseClass);
begin
AObject:=AClass.Create;
end;

вызовется именно тот виртуальный конструктор который указан по классовой ссылке AClass.

var
MVCC1:TMyBase;

CreateClass(MVCC1,TMyVeryCoolClass1);


Не знаю насколько ты, новичек, как ты говоришь, осознаешь всю предоставляемую гибкость, но вдруг осознаешь. Можешь почитать исходники TCollection, если разберешься.

Простейший пример на основе выше изложенного.
Пусть на форме будет три кнопки.
Button_CoolClass1
Button_CoolClass2
Button_VeryCoolClass1

На OnClick которых будут создаваться объекты соответствующих классов. Вместо того что бы писать три разных обработчика OnClick можно написать всего один.

type
TForm1=class(TForm)
...
Procedure FormCreate(Sender:TObject);
private
Procedure SomeButtonClick(Sender:TObject);
MyObject:TMyBase;
end;

Procedure TForm1.SomeButtonClick(Sender:TObject);
begin
if Sender is TButton then // если это кнопка
With TButton(Sender) do
if Copy(Name,1,7)="Button_" then // если это одна из тех кнопок
CreateClass(MyObject,TMyBaseClass(Tag)); // создадим объект
end;

Procedure TForm1.FormCreate(Sender:TObject);
begin
try
TButton(FindComponent("Button_CoolClass1")).Tag:=Integer(TMyCoolClass1 );
TButton(FindComponent("Button_CoolClass2")).Tag:=Integer(TMyCoolClass2 );
TButton(FindComponent("Button_VeryCoolClass1")).Tag:=Integer(TMyVeryCo olClass1);
except
end;
end;


По моему ничего не забыл.
И теперь если вдруг у нас в семействе появится еще один класс, то его внедрение будет очень очень простым.


 
KSergey   (2003-09-04 13:43) [8]

Так, хорошо.
А как им можно воспользоваться, интересно? При создании объекта всяко указываешь класс, которого объект хочешь состряпать. Так как же его виртуальностью можно воспользоваться? Мне ничего в голову не лезет подходящего...


 
Рамиль   (2003-09-04 13:43) [9]


> Конструктор объекта не может быть виртуальным.
> Это не имеет смысла.

Может человек имел ввиду
constructor TObjectName.Сreate; virtual;
Тогда это очень даже имеет смысл


 
Palladin   (2003-09-04 13:45) [10]

Угу, забыл, обработчик назначить:

Procedure TForm1.FormCreate(Sender:TObject);
begin
try
With TButton(FindComponent("Button_CoolClass1")) do
begin
Tag:=Integer(TMyCoolClass1);
OnClick:=@SomeButtonClick;
end;
With TButton(FindComponent("Button_CoolClass2")) do
begin
Tag:=Integer(TMyCoolClass2);
OnClick:=@SomeButtonClick;
end;
With TButton(FindComponent("Button_VeryCoolClass1")) do
begin
Tag:=Integer(TMyVeryCoolClass1);
OnClick:=@SomeButtonClick;
end;
except
end;
end;


+ движек форума пробелов навставлял :)


 
Skier   (2003-09-04 13:47) [11]

>Palladin © (04.09.03 13:45)
"@" зачем ?


 
KSergey   (2003-09-04 13:47) [12]

На всякий случай:

[8] KSergey © (04.09.03 13:43) писалось до постов [6] PVOzerski © (04.09.03 13:42) и [7] Palladin © (04.09.03 13:42)


 
MBo   (2003-09-04 13:48) [13]

>KSergey
Кроме уже указанного, отмечу Application.CreateForm.
Да и вся поточная система Delphi построена на использовании вирт. констр.(см. TReader, например)


 
Palladin   (2003-09-04 13:49) [14]


> Skier © (04.09.03 13:47) [11]

Можно и без "@", но предпочитаю использовать, что бы не путатся в исходниках. Все таки свойство и всетаки присваивается не что нибудь, а процедура.


 
Рамиль   (2003-09-04 13:51) [15]

Замутили что то.. virtual и dynamic это способ размещения указателя на метод в памяти.
Если метод описан как virual, то в потомке можно его перекрыть overload ом.


 
KSergey   (2003-09-04 13:51) [16]

Надо книжки однако почитать....
Но все же мне не понятно, зачем он виртуальный. Когда объект реально создается - уже известно какого именно класса он есть. Какас разница: в коде это прописать или через классовую переменную передать? Фак тот, что известен! Как же тут виртуальность-то используется?


 
Palladin   (2003-09-04 13:53) [17]


> KSergey © (04.09.03 13:51) [16]

См. пример. Если конструкторы наследников не будут виртуальными, то в любом случае в CreateClass будет вызыватся статический конструктор TMyBase.Create и тогда вся эта система ничерта не будет работать.


 
PVOzerski   (2003-09-04 13:54) [18]

>А как им можно воспользоваться, интересно? При создании объекта всяко указываешь класс,

Вот реальный пример - из исходников компилятора FPC.
Здесь tDLLScanner - класс с виртуальным конструктором Create, CDLLScanner - массив (элементы соответствуют поддерживаемым платформам) из элементов типа TDLLScannerClass=class of TDLLScanner.

procedure create_objectfile;
var
DLLScanner : TDLLScanner;
s : string;
KeepShared : TStringList;
begin
{ try to create import entries from system dlls }
if target_info.DllScanSupported and
(not current_module.linkOtherSharedLibs.Empty) then
begin
{ Init DLLScanner }
if assigned(CDLLScanner[target_info.system]) then
DLLScanner:=CDLLScanner[target_info.system].Create
else
internalerror(200104121);
KeepShared:=TStringList.Create;
{ Walk all shared libs }
While not current_module.linkOtherSharedLibs.Empty do
begin
S:=current_module.linkOtherSharedLibs.Getusemask(link_allways);
if not DLLScanner.scan(s) then
KeepShared.Concat(s);
end;
DLLscanner.Free;
{ Recreate import section }
if (target_info.system in [system_i386_win32,system_i386_wdosx]) then
begin
if assigned(importssection)then
importssection.clear
else
importssection:=taasmoutput.Create;
importlib.generatelib;
end;
{ Readd the not processed files }
while not KeepShared.Empty do
begin
s:=KeepShared.GetFirst;
current_module.linkOtherSharedLibs.add(s,link_allways);
end;
KeepShared.Free;
end;

{ create the .s file and assemble it }
GenerateAsm(false);

{ Also create a smartlinked version ? }
if (cs_create_smart in aktmoduleswitches) then
begin
{ regenerate the importssection for win32 }
if assigned(importssection) and
(target_info.system in [system_i386_win32,system_i386_wdosx]) then
begin
importsSection.clear;
importlib.generatesmartlib;
end;

GenerateAsm(true);
if target_asm.needar then
Linker.MakeStaticLibrary;
end;

{ resource files }
CompileResourceFiles;
end;


 
jack128   (2003-09-04 13:54) [19]

Вообще все полезность виртуальных конструкторов можно осознать только если пересядешь на С++ ;-)


 
Рамиль   (2003-09-04 13:56) [20]


> Вообще все полезность виртуальных конструкторов можно осознать
> только если пересядешь на С++ ;-)

Чем они в Delphi хуже интересно?


 
jack128   (2003-09-04 13:58) [21]

Тем что в Delphi они есть,а в С++ их нету ;-))


 
Calm   (2003-09-04 14:06) [22]


>
> > Вообще все полезность виртуальных конструкторов можно
> осознать
> > только если пересядешь на С++ ;-)
>
> Чем они в Delphi хуже интересно?

Чую грядет holy war!


 
KSergey   (2003-09-05 07:51) [23]

Всем спасибо!

PS
оправданием того, что, мягко говоря, сел в лужу возможно может служить лишь то, что подробности про все эти виртуализации читал только в книгах по С++, в дельфи оно и как-то само по себе нормально работает ;)


 
Юрий Зотов   (2003-09-05 08:19) [24]

> Рамиль © (04.09.03 13:51) [15]

> virtual и dynamic это способ размещения указателя на метод в памяти.

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

> Если метод описан как virual, то в потомке можно его перекрыть
> overload ом.

1. "Перекрыть" - это override, а overload - это совсем другое.
2. Динамические методы перекрываются точно так же, как и виртуальные. Разница между ними совсем не в этом.


 
Verg   (2003-09-05 08:26) [25]

Ммм, просто для наглядности, может будет полезно

VMT класса.

См. Имя Примечания
0 Отсюда и выше (смещение в +) идут адреса виртуальных методов данного класса.Сюда показывает pointer по смещению 0 в экземпляре данного класса
-4 Destroy Деструктор класса
-8 FreeInstance
-12 NewInstance
-16 DefaultHandler
-20 Dispatch
-24 BeforeDestruction
-28 AfterConstruction
-32 SafeCallException
-36 Parent Указатель на поле SelfPtr VMT предка (похож на указатель на экземпляр класса предка)
-40 InstanceSize Размер экземпляра данного класса в байтах
-44 ClassName Указатель на ShortString с именем класса
-48 DynamicTable
-52 MethodTable
-56 FieldTable
-60 TypeInfo
-64 InitTable
-68 AutoTable
-72 IntfTable
-76 SelfPtr Всегда указатель на VMT данного класса. (На эту же таблицу)


 
Рамиль   (2003-09-05 08:50) [26]


> 1. "Перекрыть" - это override, а overload - это совсем другое.
> 2. Динамические методы перекрываются точно так же, как и
> виртуальные. Разница между ними совсем не в этом.

Ошибся в написании просто:)


 
Юрий Зотов   (2003-09-05 08:53) [27]

> Рамиль © (05.09.03 08:50) [26]

Тогда неверно. Потому что если метод описан как dynamic, то в потомке его тоже можно перекрыть тем же самым override"ом.


 
Рамиль   (2003-09-05 08:58) [28]

Да знаю я все это со второго курса, не задумываясь написал, извините;)


 
Calm   (2003-09-05 09:09) [29]

2 Verg © [25]
А есть еще какая-нибудь информация на эту тему?
И откуда взята эта?

Конечно едва ли ею можно воспользоваться на практике, но для понимания некоторых вещей IMHO полезно знать.


 
MBo   (2003-09-05 09:13) [30]

>Calm
system.pas


 
Verg   (2003-09-05 09:14) [31]


> И откуда взята эта?


Сам как-то расковыривал.
Еще были форматы таблиц
-48 DynamicTable
-52 MethodTable
-56 FieldTable
-60 TypeInfo
-64 InitTable
-68 AutoTable
-72 IntfTable


Но, блин, не могу найти. Я даже статью готовил под названием "DELPHI внутри"....
Да забросил ее, некогда стало...


 
Рамиль   (2003-09-05 09:15) [32]


> system.pas

Да уж, именно там и надо смотреть:)

> А есть еще какая-нибудь информация на эту тему?
> И откуда взята эта?

Любая книжка, где описан Object Pascal.


 
MBo   (2003-09-05 09:19) [33]

>Любая книжка, где описан Object Pascal.
Ну уж прямо и любая ;)

В Лишнере есть такая информация.


 
Рамиль   (2003-09-05 09:29) [34]


> Ну уж прямо и любая ;)

Не знаю, во всех которые я читал было, значит не верная интерполяция...


 
KSergey   (2003-09-05 11:06) [35]

ЛЮДИ!!! Я ПОНЯЛ!!!! ;))

(я понимаю, что все это знаю, но позвольте поделиться своей радостью ;)

Я как раз хотел задать вопрос типа:

"Не, все же мне не понятно зачем он виртуальный. Ведь на момент создания класс-то уже известен, так зачем виртуальность?
Ведь что по сути есть "метакласс" (вообще, мне его больше нравится называть "ссылка на класс", т.к. "МетаКласс" звучит сильно заумно и лично мне нифига не понятно зачем он "мета"). Так вот, что есть этот мета класс? Это просто ссылка на таблицу VMT - и все. Надеюсь, тут я не ошибаюсь.
А раз класс знаем - в этой таблице берем конструктор (где го адрес есть) - и вызываем. Вот и все.."

Когда я раз 5 повторил этот вопрос про себя, до меня вдруг дошло! Это же таблица виртуальных методов, т.е. в ней просто не будет адреса конструктора, если он не виртуальный! По сути, видимо, в этом случае на еще на стадии компиляции компилятор постоит вызов конструктора для того класса, на который ссылается этот "метакласс", а не того класса, который в него (в переменную) будет записан.

1.Я теперь прав?

2.Только если честно, я не вижу где эта штука может быть незаменимой. Не, понятно про создания объекта того класса, который записан в переменную. Однако же, по скольку на стадии проектирования приложения я знаю какие вообще варианты возможны (я не представляю такой ситуации, когда я этого не знаю; т.е. да, могут быть условия, но я сам же явно и пропишу все варианты возможных для создания тем или иным способом классов), а следовательно - наверное это все же лишь красивый наворот, но не более? В том смысле, что он полностью заменим конструкцией вида:

case i of
1: MyObj := TObj1.Create;
2: MyObj := TObj2.Create;
3: MyObj := TObj3.Create;
end;

Тут я прав?


 
Erik   (2003-09-05 13:19) [36]

Да написать все как угодно можно, но тебе нравится красивый компактный и легко расширяемый код? Тогда запомни аксиому, что некоторые задачи типа "поточная система Delphi" надо делать с виртуальными конструкторами.


 
Calm   (2003-09-05 13:28) [37]


> Однако же, по скольку на стадии проектирования приложения
> я знаю какие вообще варианты возможны ( я не представляю
> такой ситуации
, когда я этого не знаю; т.е. да, могут быть
> условия, но я сам же явно и пропишу все варианты возможных
> для создания тем или иным способом классов

Имеем простой вьюер объектов разноообразных классов.
Классы объектов подгружаются из плугинов, в которых объявлены нужные классы. При загрузке плугина (пакета) классы регистрятся (RegisterClass). В плугине так же загружаются правила для работы с такими объектами.
Сами объекты загружаются из БД, где хранится имя класса.
С помощью FindClass получаем ссылку на класс и создаем объект класса, который заранее не известен.
Плугины могут поставляться стороними разработчиками, поэтому использовать во вьюере 200 if-ов (для каждого класса не получится).
Понятно, что конструкторы у всех классов могут быть реализованы по-разному.


 
KSergey   (2003-09-05 13:33) [38]

> [37] Calm © (05.09.03 13:28)

Хороший пример, учту. ;) Спасибо.

(впрочем, передал из стандартной ф-ции плугина все что нужно, вплоть до адресов CallBack функций - вот и все ;) но я не спорю, это просто другой подход решения той же задачи; и я их ни в коей мере не сравниваю на предмет что лучше.)


 
Calm   (2003-09-05 13:42) [39]


> впрочем, передал из стандартной ф-ции плугина все что нужно,
> вплоть до адресов CallBack функций - вот и все ;)

А по-подробнее, если не затруднит?
Мне тоже хочется узнать другой способ решения такой задачи :)


 
KSergey   (2003-09-05 14:10) [40]

> [39] Calm © (05.09.03 13:42)

Я попробую, надеюсь получится так же понятно как и у вас. ;)

Если исключить классы (пока, для простоты), то с функциональным подходом имеет такую картинку: в DLL плугина есть некая ф-ция с известным именем, которую вызываем для инициализации плугина и получении информации о нем. Эта ф-ция, например, заполняет адреса процедур (в некой структуре), к которым будет обращаться основной модуль. Ну можно по всякому это сделать. После чего основной модуль уже вызывает при необходимости ф-ции плугина по этим адресам. Можно заполнить не все адреса, если не все ф-ции реализованы в плугине - ну и т.д.
Можно и классы сюда наворотить при желании, конечно.
Примерно так.



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

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

Наверх





Память: 0.56 MB
Время: 0.009 c
1-58613
_ilya
2003-09-05 13:13
2003.09.18
Папка или файл?


1-58761
Sniffer
2003-09-06 12:39
2003.09.18
Изминение Security Attributes файла


7-58922
maxon
2003-07-08 16:57
2003.09.18
запуск от другого имени


1-58665
Дмитрий В. Белькевич
2003-09-04 16:35
2003.09.18
Печать bitmap на canvas принтера.


1-58679
McMurfy
2003-09-04 19:00
2003.09.18
Ошибка при присваивании





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский