初看<>的两个疑惑
xzgyb 2004-01-12 11:33:13 近日在看李维老师的<<Inside VCL>>,又有了两点疑惑,以前看<<delphi面向对象编程思想>>也有疑惑,不过现在又有了,呵呵,只不过是看名家的书,但心中感觉有些问题
不说不快,
疑惑1:
书中57~58中,由于没有配套光盘,只抄了部分的代码
大概的代码:
TDerived = class(TBase)
private
FData: Variant;
public
...
function PureMethod: string;
published
function MyMethod1: string;
procedure MyMethod2;
property sData: Variant read FDate write FDate;
end;
procedure TForm1.Button7Click(Sender: TObject);
var
aObj: TDerived;
sData: string;
aPtr: Pointer;
begin
sData := 'TDerived at ' + DateTimeToStr(Now);
aObj := TDerived.Create(sData, HashOf(sData));
...
ShowMethodAddress(aObj, 'MyMethod1');
aPtr := ShowMethodAddress(aObj, 'MyMethod2');
sData := MethodName(aPtr); //注意这块
sData := Format('%x : %s', [Integer(aPtr), sData]);
Memo1.Lines.Add(sData);
....
end;
function TForm1.ShowMethodAddress(aObj: TDerived; const sData: string): Pointer;
var
aPtr: Pointer;
sResult: String;
begin
try
aPtr := aObj.MethodAddress(sData);
sResult := Format('%s : %x', [sData + '位于': ', Integer(aPtr)]);
Memo1.Lines.Add(sResult);
except
on E: Exception do
begin
sResult := Format('%s : %s', [sData, e.Message]);
Memo1.Lines.Add(sResult);
end;
end;
end;
59页
书中有一段话
'有趣的是上面的程序代码可以通过调用MethodAddress取得published方法的地址,
但是对于其它种类的方法是无法取得方法地址信息的。如果我们反向调用MethodName
却无法取得某一地址的方法名称,这是有点奇怪的',
59页又有一段代码
procedure TForm1.Button8Click(Sender: TObject);
var
sData: string;
aPtr: Pointer;
begin
aPtr := Pointer(@Self.OnClick);
sData := MethodName(aPtr);
sData := Format('%x : %s', [Integer(aPtr), sData]);
Memo1.Lines.Add(sData);
end;
在60页
'因此我们可以推知MethodName似乎只会对从TComponent继承下来的类的published方法才有作用';
这段话我感觉是有问题的,第一段代码之所以用MethodName取不到方法名,是因为在
TForm1.Button7Click(Sender: TObject)中直接调用sData := MethodName(aPtr);
相当于Self.MethodName(aPtr),也就是说调用TForm1的对象的MethodName
这当然找不到aObj的MyMethod2方法名,应该调用的是aObj.MethodName(aPtr);
所以60页的这个结论不成立
疑惑2:
93页中有个测试VMT表格创建的时机的代码.
procedure TForm1.Button4Click(Sender: TObject);
var
aPn1: TPanel;
begin
aClass := aPn1.ClassType;
sClassName := 'TPanel';
ShowVMTContent(aClass); //显示VMT内容的一个函数,不再抄了
aPn1 := TPanel.Create(Self);
aClass := aPn1.ClassType;
sClassName := 'TPanel';
ShowVMTContent(aClass);
FreeAndNil(aPn1);
end;
94书中说
'在未实际创建TPanel对象前我们经由aPn1显示VMT的内容,得到的结果应该是无意义的内容。然而一旦当TPanel对象实际在内存中创建之后就可以取得TPanel的VMT中的
内容.由这个现象来看,我们可以推知VMT应该是在第一个类对象被创建时才会创建完整的VMT内容,原因是属于同一个类的所有对象都是共享一个VMT表格'
这话我又感觉有问题了,
aClass := aPn1.ClassType;
sClassName := 'TPanel';
ShowVMTContent(aClass);
这个之所以是无意义的内容,因为aPn1本身是一个指针变量,一开始指向的就是无意义的内容,而ClassType的代码如下
function TObject.ClassType: TClass;
begin
Pointer(Result) := PPointer(Self)^;
end;
所以这个取到的ClassType本身就是无意义的,
简单的来说
aClass := TPanel;
sClassName := 'TPanel';
ShowVMTContent(aClass);
这样就内容正确,这时并没有创建一个类的对象。
因此一个类的VMT创建的时机我觉得应该是在源码中第一次出现该类的名字时
创建的,换句话说应该是当编译器进行编译时发现你的源码中出现了TPanel这个词
那么就在内存中创建一个TPanel的VMT表.
以上仅是自己的一点看法,并不定正确.
书刚看了一点,继续看.