Форум: "KOL";
Текущий архив: 2006.12.24;
Скачать: [xml.tar.bz2];
ВнизНедомолвка в FAQ насчет AncestorOfObject Найти похожие ветки
← →
BenGun (2006-03-06 18:55) [0]>> В KOL нет RTTI, поскольку используется "старая" ООП-модуль (не class, а object). В итоге вместо
>> MySuper as TSmth пишем PSmth(MySuper), а вместо MySuper is TSmth пишем TSmth.AncestorOfObject(MySuper)
разве не стоит указать, что AncestorOfObject возможно использовать только в методах объекта, являющегося потомком TSmith или самого TSmith?
← →
Thaddy (2006-03-06 19:43) [1]Yup, this code is verifying, not falsifying (i.e: it does not test for impossible options, it verifies the code is valid. Scientific mistake :-)) Read Karl Popper about it.
← →
Vladimir Kladov (2006-03-06 19:52) [2]А он вообще работает? А то он долго не пахал, потом кто-то фиксил, а мне он как-то не был нужен, я и не смотрел, работает ли он вообще.
← →
Thaddy (2006-03-06 20:35) [3]Yes, but you know that generally is not good enough:
and obviously, the value of AncestorOfObject is undefined, not nil! when it fails.
Therefore, it isn"t very good code (although generally it works ;) ) It might have been in the late 10th and early 20th century. :)
← →
BenGun (2006-03-07 16:16) [4]to Vladimir Kladov
работает в указанной области видимости (еще кое где, но там глючит)
to Thaddy
I always can do before call AncestorOfObject to check for nil and it"s not a problem:)
Мужики, дело такое... В ООП да не иметь возможности проверить экземпляр объекта на принадлежность к типу - это даже не смешно, это катастрофа! нет, это просто кошмар! :( Насчет "мне он как-то не был нужен" я смею сомневаться в искренности.
P.S.
KOL - очень добротный проект, и мне хотелось бы его использовать, но без вышеупомянутой проверки это нереально, ибо
1. Привык
2. Это очень удобный механизм и неотемлемая часть ООП! Какого лешего?!
Огромное спасибо за участие (если честно, то не надеялся)
ICQ 111326219(hidden/always offline for "not in contacts")
email bgun@list.ru
← →
ECM © (2006-03-07 17:14) [5]
> не иметь возможности проверить экземпляр объекта на принадлежность
> к типу - это даже не смешно, это катастрофа! нет, это просто
> кошмар
Между прочим в КОЛ 99% контролов это TControl. И "вообще поменьше типов" - один из постулатов КОЛ. И "какого лешего"? :))
Если это Ваши типы - никто не мешает сделать свой механизм.. Если нет сил (умения ) сделать свой - посмотрите что не так в том что есть... Это не так уж сложно. (Важно то что это нужно именно Вам)
Но учтите - разницу между ComboBox-ом и ListBox-ом например (да и всеми остальными "стандартными" контролами ) - Вы не обнаружите - это всё TControl
← →
BenGun (2006-03-07 17:42) [6]to ECM
Уважаемый, безусловно меня в первую очередь интересует построение собственных классов и дальнейшее их использование(!!!). Паскаль можно задействовать не только для построения гуёв: для меня важнен комплекс - и гуй, и математика. Насчет Вашего "свой механизм" - я вижу только вариант, при котором мне надо будет создавать экземпляр объекта проверяемого типа.
>> "если нет сил (умения ) сделать свой - посмотрите что не так в том что есть... Это не так уж сложно" Не могли бы Вы поконкретнее? Очень похоже на флейм типа "ДА ТЫ НЕ НА ТОМ ЯЗЫКЕ ПИШЕШЬ!!"
С TControl"ами сейчас проверю (хотя это частная задача, имеющая отношение к проблемме весьма второстепенное)
← →
ECM © (2006-03-07 18:07) [7]
> Не могли бы Вы поконкретнее?
Конкретнее не бывает (см. KOL.PAS):class function TObj.AncestorOfObject(Obj: Pointer): Boolean;
asm
MOV ECX, [EAX]
MOV EAX, EDX
JMP @@loop1
@@loop:
MOV EAX,[EAX]
@@loop1:
TEST EAX,EAX
JE @@exit
CMP EAX,ECX
JNE @@loop
@@success:
MOV AL,1
@@exit:
end;
Смотрим, запускаем для разных классов, изучаем в отладчике... Или это надо сделать мне? :))
> С TControl"ами сейчас проверю
Это - туда же (см. KOL.PAS) :)))
З.Ы. Флейм про "лешего с гуЁм" - продолжать не стоит - не надо :))
(Вот, не хотел же отвечать на ... )
← →
BenGun (2006-03-07 18:32) [8]Увы, ассемблер для меня - черный ящик. В Kol.pas смотрю прямо сейчас (снимаю шляпу перед автором, объем работы проделан чудовищный). Вижу, что все PControl есть именно PControl и тут, видимо, подразумевается иной механизм (скорее всего сравнение с каким-нибудь classname).
И всё-таки хотелось бы услышать чего-нибудь по существу вопроса :)
Вопрос стоит: "Как же быть?" :)
← →
BenGun (2006-03-07 18:42) [9]для конкретики: бог с ними, с control"ами, что насчет наследников TObj?
← →
BenGun (2006-03-07 18:51) [10]даже так, еще конкретнее. Как мне развести следующее:
имеются типы
TAA->TA->TObj
TAB->TA->TObj
задача:
program
(...)
var
A: PA;
begin
A := NewXXX; (вирианты A, AA, AB)
if (проверка A is TA) then
Do1
else
if (проверка A is TAA) then
Do2
else
if (проверка A is TAB) then
Do3;
end;
← →
BenGun (2006-03-07 18:56) [11]хехе. ща бы меня тут волхвы похоронили :))) Оговорюсь и поправлю код (если успел)
program
(...)
var
A: PA;
begin
A := NewXXX; (вирианты A, AA, AB)
if (проверка A is TA) then
begin
if (проверка A is TAA) then
Do2
else
if (проверка A is TAB) then
Do3;
end;
end;
← →
z007 (2006-03-07 21:20) [12]Проблема знакомая. Сам с ней столкнулся при написании компонентов (http://delphimaster.net/view/11-1140304918/).
Однако:
Если это есть самопальные типы, ну сделай в них поле / property
(ftypeID:byte|word<as 2Chars>|integer<as 4 Chars>|string, наконец). Как правило, без проверки типов действительно можно обойтись, в т.ч при создании собственных компонентов. Надо только врубиться в "правила KOL".
← →
BenGun (2006-03-09 08:05) [13]:) это-то понятно. Если уж на то пошло, можно обойтись и процедурным программированием (даже блочным копированием! процедуры - буржуазная роскошь!) Речь идет о трудоёмкости. Вообще говоря, я хотел высказать пожелание подправить FAQ (втайне надеясь, что я чего-то недопонял и механизм существует). Спасибо всем, принявшим участие и авторам KOL особенно. Повторюсь: труд потрясает масштабами(!!!) и не юзать ТАКОЕ - просто преступление перед человечеством :)))))
← →
Barloggg (2006-03-09 09:21) [14]хм... все свои классы я делаю именно class"ами. никто не запрещает. да и стоит это не дорого. где-то 3-5 кб ехе-шника.
А KOL использую только для компактных окошек и контролов.
А там где мне не нужно многократное наследование или я точно знаю какой где тип то тогда использую TObj.
еще из первых уроков которые я прочел прежде чем решиться вообще скачивать и ставить себе KOL+MCK мне стало ясно, что вся мощь class тут не используется и рассчитывать на 100% альтернативу бесполезно.
мне кстати недавно понадобилось свалить в одну кучу с пяток наследников от TObj разных типов... и я сбацал "оглавление" с жестко размеченными индексами для каждого объекта которое представляет собой динамический массив of PObj.
помню как-то сбацал "главного предка" который был простым наследником с одним единственным дополнительным полем - именем текущего класса. и в конструкторе идет заполнение этого поля текущим именем... а все остальные классы наследовал от него...
← →
ECM © (2006-03-09 13:01) [15]Я вижу ясности в главном вопросе об AncestorOfObject, так и не прибавилось... Поэтому приведу тут свои соображения (решил посидеть пару часов - разобраться что к чему) - если я где-то ошибаюсь - пожалуйста поправьте. Вообще-то я считал, что в таких базовых вопросах
уже давно всё в порядке (сам я этой функцией не пользуюсь) - ну да ладно
смотрим (у меня D6 и KOL 2.34):class function TObj.AncestorOfObject(Obj: Pointer): Boolean;
asm
MOV ECX, [EAX]
// EAX на входе функции равен Self и следовательно в ECX попадает первый
// DWORD из памяти распределенной под объект. А как можно увидеть из
// ассемблерного кода функции TypeOf там лежит указатель на VMT TObj
// Эксперимент с вызовом функции напрямую (без создания
// экземпляра класса) показывает что в EAX передается указатель на некую
// ячейку памяти в которой тоже расположен указатель на VMT TObj
// Итого: ECX => VMT TObj
MOV EAX, EDX
// EAX => указатель на проверяемую переменную
JMP @@loop1
@@loop:
MOV EAX,[EAX]
//
@@loop1:
TEST EAX,EAX
//Проверка на ноль
JE @@exit
CMP EAX,ECX
// В первом же цикле сравнивается указатель на VMT с указателем на
// переменную!!!! (Предполагалось я думаю сравнивать указатели на VMT)
// Если бы во второй команде функции было MOV EAX,[EDX] то в первом
// цикле так бы и случилось....но да ладно потом выполняется
// MOV EAX,[EAX] и в EAX уже VMT проверяемого объекта - если это
// VMT TObj то во втором цикле проверки - всё закончится, а если нет?
// см. ниже
JNE @@loop
@@success:
MOV AL,1
@@exit:
end;
Если во втором цикле проверка не проходит - в EAX загружается новое значение - теперь оно берется ПРЯМО ИЗ VMT! Т.к. далее сравниваться оно будет с VMT Tobj - остается предположить что в первой ячейке VMT автор функции ждет найти указатель на родительскую (?) VMT... и тогда цикл будет продолжен до совпадения либо до корневого класса где указатель на родительскую VMT = 0 ... ?.... Что то я не припомню, чтобы VMT для старой объектной модели были указатели на предков. Ну да это несложно проверить. Создаем в программе такие классы (например как в [10]):type
PA = ^TA;
TA = object (TObj)
destructor Destroy; virtual;
end;
PAA = ^TAA;
TAA = object(TA)
end;
PAB = ^TAB;
TAB = object(TA)
end;
PTT = ^TT;
TT = class
destructor Destroy; virtual;
end;
После тщательного изучения кода получилась следующая картина - компилятор сгенерировал 4-е VMT расположенные в начале сегмента модуля. Я изучил их структуру и вот что у меня получилось(дамп пямяти):Address | Value | Desc
--------+-----------+------------------------------------
$406F2C | $00406F38 | (vmtSelfPtr ) | VMT
$406F30 | $00000018 | (vmtInstanceSize) | TA = object(TObj)
$406F34 | $00000000 | (vmtPtrOffs ) |
$406F38 | $00403EF0 | _TObj.Init |
$406F3C | $004074D4 | TA.Destroy |
--------+-----------+------------------------------------
$406F40 | $00406F4C | (vmtSelfPtr ) | VMT
$406F44 | $00000018 | (vmtInstanceSize) | TAA = object(TA)
$406F48 | $00000000 | (vmtPtrOffs ) |
$406F4C | $00403EF0 | _TObj.Init |
$406F50 | $004074D4 | TA.Destroy |
--------+-----------+------------------------------------
$406F54 | $00406F60 | (vmtSelfPtr ) | VMT
$406F58 | $00000018 | (vmtInstanceSize) | TAB = object(TA)
$406F5C | $00000000 | (vmtPtrOffs ) |
$406F60 | $00403EF0 | _TObj.Init |
$406F64 | $004074D4 | TA.Destroy |
--------+-----------+------------------------------------
$406F68 | $00406FB4 | (vmtSelfPtr ) | VMT
$406F6C | $00000000 | (vmtIntfTable ) | TT = class
$406F70 | $00000000 | (vmtAutoTable ) |
$406F74 | $00000000 | (vmtInitTable ) |
$406F78 | $00000000 | (vmtTypeInfo ) |
$406F7C | $00000000 | (vmtFieldTable ) |
$406F80 | $00000000 | (vmtMethodTable ) |
$406F84 | $00000000 | (vmtDinamicTable) |
$406F88 | $00406FB8 | (vmtClassName ) |
$406F8C | $00000004 | (vmtInstanceSize) |
$406F90 | $00401000 | (vmtParent) VMT TObject
$406F94 | $004028B0 | TObject.SafeCallException
$406F98 | $004028BC | TObject.AfterConstruction
$406F9C | $004028C0 | TObject.BeforeDestruction
$406FA0 | $004028C4 | TObject.Dispath
$406FA4 | $004028B8 | TObject.DefaultHandler
$406FA8 | $00402794 | TObject.NewInstance
$406FAC | $004027B0 | TObject.FreeInstance
$406FB0 | $004027EC | TObject.Destroy
$406FB4 | $004074EC | TT.Destroy
$406FB8 | $90545402 | #90"TT"#02 (ClassName)
vmtSelfPtr (VMT - 12) - указатель на собственно VMT. Delphi резервирует (и как бы скрывает от программиста) первые служебные ячейки VMT. Значение как
можно заметить - указывает на начало собственно таблицы виртуальных
метедов (т.е. на первый виртуальный метод). Имеено значение передается
записывается в первую ячейку памяти выделенной под объект.
vmtInstanceSize (VMT - 8) - размер памяти который необходимо выделить для размещения объекта. Равен сумме размеров полей объекта + 4 (для хранения указателя на VMT). Именно это значение возвращается по SizeOf для объекта.
vmtPtrOffs (VMT - 4) . Смещение в памяти выделенной под объект, где лежит указатель на VMT.(Это видно при анализе System.ObjSetup) Как видно это значение всегда (?) нулевое. Т.е. указатель на VMT всегда (?) расположен в первой ячейке памяти объекта (т.е. первое и неявное поле типа Pointer)
Как видно в VMT для объектной модели - нет никаких признаков наличия
указателя на VMT предка. И следовательно определить способом предлагаемым в AncestorOfObject кто есть предок просто невозможно!
Да и честно говоря - способа это сделать я не вижу. Сравнение кода System.pas для других версий Delphi показывает что структура VMT для
старой объектной модели везде (незнаю только что в D2, но скорее всего и там тоже) одинакова.....:(
...Да и еще - использование этой функции в конце-концов может привести к AV. Т.к на третьем этапе в AX попадает указатель на первый VM объекта,
на четвертом - строится указатель из первых 4 байт кода первого VM и дальше катится неконтроллируемо (хорошо если по пути случайно попадется нулевая ячейка) - и (как было в моем случае) падает с AV.
Может эта функция была написана для FPC и там в VMT есть указатели на VMT предка - не знаю...
Если есть кто из авторов этой функции ? Может кто пояснит ситуацию?
З.Ы. Кстати из дампа VMT для TT видно, что объявления
TT = class
...
end;
TT = class(TObject)
...
end;
это действительно одно и тоже ... :))
← →
ECM © (2006-03-09 18:23) [16]
> z007 (07.03.06 21:20) [12]
> Если это есть самопальные типы, ну сделай в них поле / property
> Barloggg (09.03.06 09:21) [14]
> помню как-то сбацал "главного предка" который был простым
> наследником с одним единственным дополнительным полем
> BenGun (07.03.06 18:42) [9]
> для конкретики: бог с ними, с control"ами, что насчет наследников
> TObj?
Кстати, для этих целей вполне можно использовать поле TObj.Tag. В конструкторе потомка заносить туда "уникальный" номер (для TObj это будет 0). Потом анализировать ...
← →
GMax (2006-03-09 23:48) [17]а ещё можно USE_NAMES и давать осмысленные имена :)
← →
ECM © (2006-03-10 09:27) [18]
> GMax (09.03.06 23:48) [17]
Согласен, но это уже конкретизация экземпляра класса(объекта), а речь выше шла о идентификации класса объекта (типа) - поэтому в случае осмысленных имен - придется делать их парсинг, что, вобщем,является более "дорогостоящей" операцией, чем сравнение двух целых чисел
:))
Страницы: 1 вся ветка
Форум: "KOL";
Текущий архив: 2006.12.24;
Скачать: [xml.tar.bz2];
Память: 0.54 MB
Время: 0.056 c