一个小问题: 类的地址。。。?(200分)

前面都差不多
我對“滞后联编”這個詞有點反感,覺的它有點導觀眾,把問題神秘化
所謂的“滞后联编”應該是說類在內存中初始化時確定虛方法的地址.
“滞后联编”發生在類在內存中初始化時,而不是在對象創建時,再次強調對象只是
一個類指針加一堆數據,和方法無關

假如 Tobject TA
有虚方法 A B
Ta 在內存中初始化時,會建立VMT
它可能會是這樣的
a方法地址,b方法地址

TB 繼承於TA, 在TB類初始化時,如果你有Overload A,b方法
則TB會單獨建立 A,B方法的代碼
它的VMT是這樣的
a方法新地址,b方法新地址

類在調用方法時是按方法在 vmt中偏移量來進行尋址的,和方法名沒甚麼關係
這就是繼承的實現原理

在回來說多態就簡單了,甚麼 父類=子類 那麼難理解
其實就實就是強行地把 父類 的 ptrVMT - 76 轉向為子類的 ptrVMT - 76
就是那麼簡單







 
lqy:
你来看,
procedure TForm1.Button7Click(Sender: TObject);
var
P: Pointer;
begin
P := nil
//P 赋值为一个乱七遭八的值,下面始终调用 ShowIt()不出错 !
TExample(P).ShowIt
//I'm TExample
end;

在执行:TExample(P).ShowIt
时,是如何找到 ShowIt 方法的呢?
 
上面我说过,方法不属于对象。而属于类。所以类的实例共享方法空间。
所以你上面的调用没问题。
 
同意:wr960204,
这和java中的static方法一个道理
 
我也同意wr960204的观点,在delphi高手突破里面有详细的解释!
类的数据成员在创建了对象后才可以访问。而方法自创建类时就可以访问了。
 
Delphi在编译时,把ShowIt编译成了静态方法
只要执行这个类的ShowIt,不管他是通过哪一个实例调用的
都会将指针指向已编译好的虚拟方法表中该过程的指针
就是说把调用该方法的实例忽略了
 
碧血剑:
能不能详细解释一下?

woyaoying:
“类的数据成员在创建了对象后才可以访问。而方法自创建类时就可以访问了”
这点我知道,可以访问那是肯定的,可是,究竟是如何访问的呢?
要访问一个方法,总要找到方法的入口来吧,
在执行:TExample(P).ShowIt
时,是如何找到 ShowIt 方法的呢?


 
Delphi对于每一个注册的类,都对应一个虚拟方法表VMT
我觉得就是从那个表了找的,具体的过程我也...
你到网上搜一下Delphi+虚拟方法表
应该能找到答案,
别忘了告诉我
 
類方法通過類的 VMT 來訪問,
類名如何對應到實際的地址,就是編譯器的事了
那要問暴爛才知道,


 
找到答案了!

正如lqy所说!
是从 TExample 入手找的,因为,TExample = VMT,
ptr普通方法表入口 = ptrVMT - 52

执行:TExample(P).ShowIt
时,TExample(P)<-->方法的Sender参数,
跟调用ShowIt几乎没有关系!

不知大家因为如何?
 
結案吧
你這個問題,害我打字打的手都軟了 :)
 
好的,今天结 !
谢谢 lqy, 谢谢大家 !

 
小雨哥推荐的文章非常的好!
里面的几位大虾的回答实在是精彩,
虽然其中有一点点小失误,但后来都纠正了。
 
最后一个问题:

一位网友给我推荐一本书,《Delphi 5技术手册》(O'Reilly 著)
里面介绍了Delphi对象模型,运行时类型信息(RTTI),
我只是想看看这两部分,不知道哪里有电子书可以下载?
 
哎呀,错了,错了,
普通方法表入口 <> VMT - 52

刚刚看到一篇文章:
VMT - 52 是 publish 的方法。
 
类的非虚方法也是通过 VMT 来找到函数入口的,
那么,根据 VMT 偏移多少是类的非虚方法的入口地址呢? 
 
在 VMT 中,什么地方是非虚方法的入口呢?
我看了几遍 System.pas 中的定义,觉得可能在 vmtMethodTable (- 52) 处,可是
看到一篇文章说,vmtMethodTable处是 publish 部分申明的方法,
那么,如果这样的话,类的普通方法入口究竟在 VMT 的什么地方?

vmtSelfPtr = -76
//VMT
vmtIntfTable = -72
//interface table
vmtAutoTable = -68
//Automation information table
vmtInitTable =-64
//instance initialization table
vmtTypeInfo = -60
//RTTI (type information table )
vmtFieldTable = -56
//RTTI (publish部分的:field definition table )
vmtMethodTable = -52
//RTTI (publish部分的:method definition table )
vmtDynamicTable = -48; //DMT
vmtClassName = -44
//RTTI ClassName
vmtInstanceSize = -40
//instance size in bytes
vmtParent = -36
//pointer to a pointer to ancestor class
vmtSafeCallException = -32
//[-32 → -4]是 TObject 的虚方法
vmtAfterConstruction = -28;
vmtBeforeDestruction = -24;
vmtDispatch = -20;
vmtDefaultHandler = -16;
vmtNewInstance = -12;
vmtFreeInstance = -8;
vmtDestroy = -4;
...
下面是用户定义的虚方法入口指针
 
关注此题,挺精彩的.
 

類的普通方法在編譯期已經固化,就像一個全局函數一樣使用
如果你在Delphi中用匯編就會明白
調用虛方法
其中 EDX 保存類指針
CALL DWORD PTR [EDX + VMTOFFSET TMYClass.MyVirtualMethod]
而靜態方法是
CALL TMYClass.MyMethod

上面也可以看出類方法調用和對象沒有關係
至於靜態方法的指針是如何得到,是編譯器的事,就像我們不需要知道
類指針如何得到一樣



 
lqy:
//至於靜態方法的指針是如何得到,是編譯器的事,就像我們不需要知道
//類指針如何得到一樣

类的指针我们是知道的,
在应用程序初始化时将为每一个类分配空间。这个时候,类指针就知道了,
而且是一个全局变量,每个类有其固定地址,在应用程序生命周期内不会改变。

唉,这个问题快接近尾声了,没想到还是想不通最后一点,
类的非虚方法究竟在 VMT 的什么地方,究竟如何得到非虚方法的入口指针呢?
究竟在哪里。。。???
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
顶部