Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2006.12.24;
Скачать: CL | DM;

Вниз

Недомолвка в 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 вся ветка

Текущий архив: 2006.12.24;
Скачать: CL | DM;

Наверх




Память: 0.54 MB
Время: 0.042 c
15-1165010827
ProgRAMmer Dimonych
2006-12-02 01:07
2006.12.24
Затронули тут с Колдуном тему ещё до того как...


15-1165092903
AN\ndrey
2006-12-02 23:55
2006.12.24
Подскажите где скачать ServicePack для Delphi 7 ?


3-1160572987
Rule
2006-10-11 17:23
2006.12.24
Подскажите пожалуйста где взять формальную граматику T-SQL(MSSQL)


2-1165299305
AHTOLLlKA
2006-12-05 09:15
2006.12.24
ICQ протокол


2-1165425952
Ezorcist
2006-12-06 20:25
2006.12.24
Удалить из списка элементы, удовл. условию.