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

上面不是說了嗎 非虚方法不在 VMT 中
TMYClass.MyMethod() 就是非該方法的入口指针
你可以把它看做是一個名為 <TMYClass.MyMethod>的一個普通方法
 
lqy:
哦,原来不在 VMT 中啊,难怪,
TMYClass.MyMethod() ,TMyClass 在哪里出现的?
能不能解释一下?
 
To xbl :
非虚方法不再VMT中,它是早绑定的(编译期绑定).在生成Exe或Dll的时候地址就已经
定好了.
你完全可以把它看成一个普通方法,但它与普通方法有一点不同,它有一个隐含的
参数:Self(类的实例的指针).当调用的时候要把此参数传进去(由编译器执行,不用你
自己坐).
如果你的成员方法与类的实例无关(没有用到数据成员),你可以不创建类的实例就可以
调用它.
比如下面的例子不会出错:
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TMyClass = Class
public
Procedure Test;
end;
var
Form1: TForm1;

implementation

{$R *.dfm}
procedure TMyClass.Test;
begin
ShowMessage('Called!');
end;
procedure TForm1.Button1Click(Sender: TObject);
var
a:TMyClass;
begin
a.Test;
end;

end.


 
TMYClass.MyMethod()在那里?
Delphi在编译的时候已经把这种方法编译成一个固定的地址:
以后每遇到调用的时候
比如 a.MyMethod()的时候,就判断a的类型是不是TMYClass,如果是
就Call 那个地址.
而在你所有单元中及其Uses列表的单元中,在interface部分定义的类的信息
在编译的时候也被写到Exe 或Dll文件中了.
 
xbl你拉我过来干什么?楼上倒数第二个帖子里面TMyClass只是一个例子而已吧?

我不用delphi转战java已经好久啦,看到现在delphibbs还是人才济济,由衷地感到高兴。
 
在Exe或Dll启动的时候,它们以内存映射的方式被调入内存.
这段内存区域叫静态区,包括所有的全局变量和类的信息、代码.
它们的生命期与进程相同,所以函数是早就存在了,用不着等类的实例
被创建 。
 
xeen:
你上面说的我知道了,我问之前我也这样测试过了,你看我的问题中的测试1就是
像你这样测试的!我看了大家的回复,现在明白了为什么会那样。
刚开始,我错误的认为:非虚方法在 VMT 中,原来不在呢,难怪我在
System单元的VMT常量定义的地方怎么也找不到!
当我们执行虚方法时,是通过VMT 来找到方法的入口地址的,那么,执行非虚方法
时,也一定要找到非虚方法的入口地址吧,究竟是如何找到的呢?
在我们的对象指针中,前面4字节是VMT,后面是指向数据段,我们知道的恐怕就这么多
了吧,据说,在申明一个类后,编译应用程序时,会创建一个全局的类,类的方法其实
也是全局的,并且,在方法的名称后编译器还会自动加上一些其他的字符,比如$%@#等等。
那当我们执行一个非虚方法时,是如何找到这个非虚方法的入口地址的呢?

我为什么会突然想到这个问题呢?
你还记得我上次问过一个这样的问题吗:“跨过类去继承祖先类的私有方法”?
上次许多好心人给我答复了,提供了几种解决方法。你上次也给我答复了,
我按照你那样测试,果然是可以实现,于是我就结帖了,但是,那刚好是一个特例,
我后来测试时发现:当在函数中加入了参数,问题就来了,的确,是可以调用祖先类
中定义的私有方法,但是却不能起到设置私有数据的功能。我想再问你,可惜的是,
当时我已经结了帖,那时不知道怎么可以找到你 ^-^
在那个帖子中,Another_eYes 提供了修改父类私有变量的方法,后来我也看到了
Aimingoo 写的那篇文章《跨单元访问类的私有变量》,刚好可以解决问题。
虽然问题解决了,但我心里总在想:”当我们调用一个类的方法时,其具体过程是什
么样子的呢” ,由于当时有其他事情耽搁,昨天,我突然看见以前做的笔记,所以,
我就来这里问了。
 
[blue]那当我们执行一个非虚方法时,是如何找到这个非虚方法的入口地址的呢.[/blue]
不用我们找啊,编译的时候那就是一个确定值.(这根虚方法不同)
那个值已经直接都写到Exe文件中了,但编译器不会告诉我们那个值是什么,
[red]它暗箱操作-:([/red]
 
xeen:
虽然地址已经确定,但问题是,TMyClass 可能有很多的方法,比如:MyMethod1,
MyMethod2,...当我们调用 a.MyMethod2 时,编译器是如何将 MyMethod2 这个名称
映射到它所对应的那个地址呢?
 
曹晓钢:
不好意思,我叫你时,刚好是倒数第二,因为后来几位好心人给我回复了,
因此,倒数第2变成了倒数第8 ^-^
 
那就编译器内部的事情了,只能猜想了.
它很可能建了一个名字和地址的对应表.但没有告诉我们怎么获取它.
 
Xeen:
上面我说得不是很清楚,我得意思是:
编译器是如何将我们调用的方法名称(比如 MyMethod2)影射到那个方法所对应的
已经在编译期间就确定的地址?
 
xeen:
你说的是,我只是一时好奇而已,就算猜中了,恐怕也没有什么很大的意义,
我猜了一个下午也没有猜出来 ^-^
非常谢谢你,明天过来结帖 !
 
//编译器是如何将我们调用的方法名称(比如 MyMethod2)影射到那个方法所对应的
//已经在编译期间就确定的地址?
你需要看一下《编译原理》:)
在扫描源程序时,遇到了方法的实现的时候,要生成相应的代码。在这段代码生成
前,已经生成了一些代码,于是这个方法的地址肯定是在当前已经生成的代码的最
后,这个“最后”的值是多少?比如(我说比如)你把生成的代码一条一条加入一
个TList,那么当前的TList.Count就是下一条要生成的代码的地址,也就是你即将
生成的方法的入口地址。
然后将该方法的名字和这个地址一起填入一个方法表(编译期间才有),那么在遇
到(静态)方法调用的时候,就根据方法名字去查这个表,得到要调用方法的入口
地址,就根据这个地址生成相应的代码(如“call 1234”,这个1234由查表求得)

 
啊,原来是 beta ,好久不见你了 ^-^
我没有看过《编译原理》,
原来,果然是有一张名字和地址的对应表,你是怎么知道的?
 
谢谢大家,
 
谢谢大家,分不多,请各位笑纳 !
 
//原来,果然是有一张名字和地址的对应表,[red]你是怎么知道的?[/red]
正在赶写《编译原理》的试验报告:)

 

Similar threads

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