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

Вниз

Определение адреса конструктора   Найти похожие ветки 

 
Ученик   (2002-07-16 16:13) [0]

Можно по адресу класса определить адрес конструктора объектов этого класса ?

var
P : Pointer;
begin
P := TBitmap;

Необходимо вычислить адрес TBitmap.Create, используя P, возможно ли ?


 
Skier   (2002-07-16 16:20) [1]

>Ученик
Зачем ?
Что хочешь сделать ??


 
Ученик   (2002-07-16 16:23) [2]

>Skier
Вызывать по адресу класса создание объектов этого класса, с компонентами все понятно, там constructor; override;, а вот если от TPersistent или TObject ????


 
Skier   (2002-07-16 16:27) [3]

>Ученик
для TPersistent копай :
- RegisterClass
- UnRegisterClass
- RegisterClasses
- UnRegisterClasses
- FindClass
- GetClass





 
Ученик   (2002-07-16 16:29) [4]

Вызывается конструктор TObject


 
Skier   (2002-07-16 16:30) [5]

>Ученик
В догонку :
Почитай про метаклассы.


 
Skier   (2002-07-16 16:32) [6]

>Ученик
А почему TObject у тебя же TBitmap ?


 
Digitman   (2002-07-16 16:38) [7]

ну, к примеру :

showmessage(inttohex(integer(@ TBitmap.Create), 8));

А если метод-конструктор с интересующим тебя именем объявлен как overload ? Что тогда ?

И - зачем это тебе ? Если не секрет ?



 
Ученик   (2002-07-16 16:41) [8]

>Skier
var
P : TPersistentClass;
begin
RegisterClasses([TBitmap]);
P := GetClass("TBitmap");
if P <> nil then
P.Create;
Вызывается TObject.Create

>Digitman
Вызывать по адресу класса создание объектов этого класса.


 
Digitman   (2002-07-16 16:42) [9]

Ну, предположим, вызовешь ты конструирующий метод класса ..
А экземпляр-то собственно кто будет за тебя создавать ?


 
Skier   (2002-07-16 16:48) [10]

>Ученик


type
TBitmapClass = class of TBitmap;

var
P : TBitmapClass;
begin
RegisterClasses([TBitmap]);
P := TBitmapClass(GetClass("TBitmap"));
if P <> nil then P.Create;


 
Ученик   (2002-07-16 16:53) [11]

>Digitman
Экземпляр то создается, и P.Create.Free вызовет TBitmap.Destroy, только вот конструктор вызвать проблема.


 
Ученик   (2002-07-16 16:56) [12]

>Digitman
Экземпляр то создается, и P.Create.Free вызовет TBitmap.Destroy, только вот конструктор вызвать проблема.
>Skier
TBitmap взят для примера, на его месте может быть любой другой.

Есть какая-то таблица методов, конструкторы там не постоянном месте ?


 
Digitman   (2002-07-16 17:39) [13]

>Ученик

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

тело метода-конструктора этим не занимается, его задача - инициализация уже существующего экземпляра


 
Ученик   (2002-07-16 17:46) [14]

>Digitman
Я не знаю ответа, я еще только учусь, просто попробуйте выполнить код который указан выше, объекты создаются,
не вызывается конструктор определенный именно для них


 
Skier   (2002-07-16 17:55) [15]

>Ученик
К сожалению, у потомков TPersistent конструктор не
перекроешь (override).
Это можно делать только начиная с TComponent :(


 
Digitman   (2002-07-16 17:56) [16]

>Ученик

Конечно , объект будет создаваться в этом примере ! В этом и сомнений нет )

Но ведь в этом примере работу по внедрению и вызову кода создания экземпляра неявно выполняет за тебя компилятор ...

Ты же хочешь вызвать некий метод-конструктор в run-time просто как некую процедуру инициализации экземпляра. Вопрос - какого экземпляра ? Об этом придется заботиться самостоятельно ...

Еще один вопрос - а как ты надеешься вызывать метод-конструктор, даже зная его адрес, если он имеет один или более (заранее неизвестно) параметров ?



 
Ученик   (2002-07-16 18:16) [17]

>Digitman
>Ты же хочешь вызвать некий метод-конструктор в run-time просто >как некую процедуру инициализации экземпляра.

Я хочу вызвать конструктор объекта, по-моему он должен делать все, по-крайней мере кроме вызова TObject.Create там больше ничего нет. С несколькими параметрами действительно беда, но на это хотелось пока закрыть глаза, хотя какие-то странные сообщения мелькают в Delphi, если библиотеки компонентов не соответствуют друг другу.


 
Юрий Зотов   (2002-07-16 18:25) [18]

> Ученик

Что-то все у Вас запутано как-то. Объясните просто - что нужно сделать? Создать некомпонентский объект, зная ссылку на его класс? Или что-то другое?

А Ваш пример

type
TBitmapClass = class of TBitmap;

var
P : TBitmapClass;
begin
RegisterClasses([TBitmap]);
P := TBitmapClass(GetClass("TBitmap"));
if P <> nil then P.Create;

полностью эквивалентен самому обычному вызову TBitmap.Create. Зачем такие навороты?


 
Ученик   (2002-07-16 18:29) [19]

>Юрий Зотов
Вы чего-то напутали, это не мое.


 
Skier   (2002-07-16 18:31) [20]

Это моё. Просто я-то думал что Ученик хочет иметь
дело с наследниками TBitmap-а.
Он что-то другое задумал:)


 
[NIKEL]   (2002-07-16 18:36) [21]

по моему адреса деструктора и конструктора получить невозможно...


 
Skier   (2002-07-16 18:39) [22]

>[NIKEL]
showmessage(inttohex(integer(@TBitmap.Create), 8));

Чем тебе не адрес ? :)


 
Юрий Зотов   (2002-07-16 18:48) [23]

Действительно напутал, приношу свои извинения.

Н в чем же, все-таки вопрос? Понимаете, я не зря спрашиваю. Я уточняю потому, что примерно догадываюсь, что Вы хотите и знаю, как это делается. Но чтобы говорить, нужно не догадываться, а быть полностью уверенным.


 
Ученик   (2002-07-16 19:11) [24]

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


 
vuk   (2002-07-16 19:18) [25]

to Digitman:
>тело метода-конструктора этим не занимается, его задача -
>инициализация уже существующего экземпляра
....
>Ты же хочешь вызвать некий метод-конструктор в run-time просто
>как некую процедуру инициализации экземпляра. Вопрос - какого
>экземпляра ? Об этом придется заботиться самостоятельно ...

Здесь Вы не правы. Созданием экземпляра занимается именно конструктор. И получить его адрес можно, и вызвать тоже можно (если знать как). Только вот единственное - лучше этого не делать. :o)


 
vuk   (2002-07-16 19:25) [26]

to Ученик:
Экземпляр создать можно, но не всегда можно это сделать корректно. Например для наследников TComponent это делается просто (там имеется виртуальный конструктор), а вот для других классов это может быть проблематичным.


 
Ученик   (2002-07-16 19:27) [27]

>vuk
С другими как раз и вопрос )))


 
vuk   (2002-07-16 19:32) [28]

Если Вам нужно создавать экземпляр _любого_ класса, то такая задача в общем виде не решается, поскольку у каждого класса свой конструктор и он ни в каких таблицах не прописан.


 
Ученик   (2002-07-16 19:36) [29]

>vuk
>...ни в каких таблицах не прописан.

жаль


 
Digitman   (2002-07-17 10:02) [30]

>vuk

Здесь есть вот какие тонкости :

Если перед вызовом конструирующего метода некоего класса РОН dl = 1, то непосредственно перед инициализацией экземпляра будет вызвана системная процедура ClassCreate, отвечающая за генерацию экземпляра. В противном случае (РОН dl = 0) будет произведена только попытка инициализации, и это приведет к исключению при отсутствии экземпляра.

Все inherited-конструкторы вызываются с dl = 0.

Вызов любого конструирующего метода любого класса всегда предваряется занесением в РОН eax адреса VMT

Кр.того, если конструирующий метод класса имеет параметры, их также нужно передавать : первый параметр (в порядке их перечисления в декларации конструктора) - в РОН ecx, остальные - последовательным занесением в стек.

>Ученик

Всю эту последовательность действий формирует компилятор "прозрачно" для программера.

Незнание этих фактов при явном (по факт.вычисленному адресу) вызове конструктора обязательно приведет к исключительной ситуации.



 
Ученик   (2002-07-17 10:10) [31]

>Digitman
Если что-то надо, можно и на встроенном ассемблере написать, только вот похоже адреса то нету, в любом случае, спасибо.


 
Игорь Шевченко   (2002-07-17 10:20) [32]

Адрес деструктора прописан в таблице VMT со смещением -4
(vmtDestroy)


 
Digitman   (2002-07-17 10:32) [33]

>Ученик

Как это - нет ? Вот же он !

procedure TfMain.ButtonXClick(Sender: TObject);
var
var
p: procedure;
c: TClass;
t: TObject;
begin
p:= @TComponent.Create;
c:= GetClass("TComponent");
asm
mov dl,1 // создавать экземпляр
mov eax, [c] // VMT
mov ecx, 0 // Owner = nil
call dword ptr [p] // собственно - вызов конструктора по адресу
mov [t], eax // результат - ссылка на созданный и иниц-ный экз-р
end;

t.free; // разрушение созданного объекта

end;


 
Ученик   (2002-07-17 10:52) [34]

>Игорь Шевченко
Речь шла о конструкторе
>Digitman
У нас проблема с вызовом конструкторов объектов порожденных от TObject и TPersistent, с компонентами проблем нет у них конструктор override; и все вызывается обычным образом
TComponentClass(FindClass("Имя класса")).Create(AOwner)


 
vuk   (2002-07-17 10:58) [35]

>Здесь есть вот какие тонкости
Я именно об этом. Вообще говоря, можно написать то, что написали Вы несколько проще. Если вспомнить, что конструктор - функция, возвращающая созданный экземпляр, то все просто. Конструктор без параметров можно представить примерно так:

type
TSimpleConstructor = function (ClassRef : TClass) : TObject; register;
соответственно конструктор TComponent будет иметь вид

type
TComponentConstructor = function (ClassRef : TClass; AOwner : TComponent ) : TObject; register;

Тогда вызов делается проще. Предположим, что в вышем примере переменная p имеет тип TComponentConstructor и содержит адрес конструктора, тогда его вызов будет примерно следующим:
asm
mov dl, 1
end;
t := P(c, nil);

Вот только в приведенном Вами примере все это будет лишним, поскольку все то же самое можно сделать проще, поскольку у наследников TComponent есть виртуальный конструктор и все действия, приведенные выше не особо нужны. Автору вопроса в решении его задачи это ни коим образом не поможет, поскольку он не знает, какого класса экземпляры он будет создавать и следовательно не будет иметь возможности получить адрес конкретного конструктора (у Вас это сделано явно в выделенной строке).
А с наследниками TComponent все просто. Предположим, что в переменной A содержится экземпляр какого-то наследника TComponent, тогда:
C := TComponentClass( A.GetClass ).Create( nil );



 
Digitman   (2002-07-17 11:16) [36]

>vuk
>>Автору вопроса в решении его задачи это ни коим образом не поможет

Разумеется, не поможет ! И я об этом говорю, только вот он никак это , видимо, не уразумеет.

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

>Ученик

TComponent - прямой наследник TPersistent, и непонятно в таком случае, какие у тебя сложности, если ты говоришь, что конструируешь любого наследника TComponent без проблем.


 
Ученик   (2002-07-17 11:26) [37]

>Digitman
>И я об этом говорю, только вот он никак это , видимо, не >уразумеет.

Я уже давно остановился Ученик (16.07.02 19:36)

>TComponent - прямой наследник TPersistent, и непонятно в таком >случае, какие у тебя сложности, если ты говоришь, что >конструируешь любого наследника TComponent без проблем.

Внимательности вам не хватает мастера (Digitman, Юрий Зотов), внимательности, а так цены бы вам не было ))), так много и хорошо пишете про простые вещи.






 
Digitman   (2002-07-17 11:56) [38]

>Ученик

Я вот не вижу, что ты "остановился" ...
Так ты до сих пор и не смог вразумительно объяснить суть проблемы...

Тебе ж сказали уже - в любом случае нужно заранее знать класс зарегистрированного объекта, иметь ссылку на дескриптор класса и иметь декларацию его конструктора . Только тогда с помощью VMT можно вызывать конструирующие методы класса с приведенными выше оговорками.


 
Ученик   (2002-07-17 12:03) [39]

>Digitman
Внимательности, внимательности и еще раз внимательности, прочитайте еще раз эту страницу.


 
Digitman   (2002-07-17 12:40) [40]

>Ученик

Чушь. В данном случае именно ты невнимателен.

Цитирую тебя :

(1)
>>Необходимо вычислить адрес TBitmap.Create, используя P, >>возможно ли ?

(2)
>>Вызывается конструктор TObject


Вот - еще раз - код, отвечающий на твой вопрос (1) и опровергающий твое утверждение (2)

Тот самый твой TBitmap - не имеющий к TComponent отношения.


procedure TfMain.ButtonXClick(Sender: TObject);
var
var
p: procedure;
c: TClass;
t: TObject;
begin
p:= @TComponent.Create; // вот тебе адрес
RegisterClass(TBitmap);
c:= GetClass("TBitmap");
asm
mov dl,1
mov eax, [c]
call dword ptr [p] // вот тебе создание объекта TBitmap
mov [t], eax
end;

t.free; // вот тебе разрушение созданного объекта TBitmap

end;


Отрассируй и убедись сам !!!



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

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

Наверх




Память: 0.55 MB
Время: 0.008 c
1-95309
AlexAlex
2002-07-16 18:00
2002.07.29
Программное управление положением подписей (Mark) в TChart


3-95201
alexvan
2002-07-06 14:36
2002.07.29
Как в DBGrid значение в поле


1-95408
Aric
2002-07-16 12:01
2002.07.29
Insert/Delete/Edit для TreeView


1-95394
AlexanderVasjuk
2002-07-15 16:55
2002.07.29
Lame API


7-95587
Пушкарев Павел
2002-04-30 16:37
2002.07.29
Как определить Материнскую плату, звуковую и венчестер





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