李维的inside vcl的确有一些bug,希望大家提出方便讨论~
李维的inside vcl的确有一些bug,希望大家提出方便讨论,并注明页码
贴 reallike 发现的几个问题:
问题一:
书中的论述是这样的:
{ ======================================================== }
让我们看一个范例,在下面的程序代码中声明了如下的TBase类:
TBase = class(TObject)
private
{ Private declarations }
iRef : Integer;
...
end;
要建立TBase对象时除了可使用下面的建构函数:
aBObj := TBase.Create;
我们也可以使用如下的程序代码:
var
aBObj : TBase;
aObj : TObject;
begin
...
try
aObj := TObject(TBase.NewInstance);
aBObj := TBase(aObj.Create);
// 上面一句可能存在问题。
// 按照这种写法,调用的是 TObject.Create 而不是 TBase.Create。
// 那么这种写法和 aBObj := TBase.Create; 是不等价的。
//
// 举个例子,假设 TBase.Create 函数体内有一条赋值语句 iRef := 100;
// 当我们使用通常的对象创建方法,即 aBObj := TBase.Create;
// 此时,当对象构造完毕时 aBObj.iRef 是等于 100 的。
// 但如果按照现在的写法,aBObj.iRef 仍然为 0。
// 但如果这个语句改成 aBObj := TBase(aObj).Create; 就不会有问题。
//
// 李维在这里举了一个 TApplication.CreateForm 的例子来验证他的说法。
// 但有一点他没有注意到 TComponent 的构造函数 Create 是 virtual 的。
// 而 TObject.Create 却不是 virtual 的。
...
finally
FreeAndNil(aBObj);
end;
end;
问题二:
书中的论述是这样的:
{ ======================================================== }
因此我们可以推知 MethdodName 似乎只会对从 TComponent 继承下来的类的 published 方法才有作用。
//
// 李维得出这个结论是来源于下面的这个例子
//
procedure TForm1.Button7Click(Sender: TObject);
var
aObj : TDerived;
sData : String;
aPtr : Pointer;
begin
sData := 'TDerived at ' + DateTimeToStr(Now);
aObj := TDerived.Create(sData, HashOf(sData));1
...
ShowMethodAddress(aObj, 'MyMethod1');
aPtr := ShowMethodAddress(aObj, 'MyMethod2');
sData := MethodName(aPtr);
// 由于此处运行的结果是 sData = ''; 也就是没能获得相应的 MethodName
// 因此,李维得出了上述结论。
// 但是我认为这个结论是错的。因为这个语句有问题。
//
// sData := MethodName(aPtr); 实际上调用的是 TForm1.MethodName 函数
// MyMethod2 根本不是 TForm1 的成员函数,当然获取不了 MethodName。
//
// 如果该语句改成 sData := TDerived.MethodName(aPtr);
// 或者改成 sData := aObj.MethodName(aPtr);
// 都能够获得正确的 MethodName。
//
// 因此,MethdodName 对从 TObject 继承下来的类的published方法都有作用。
// 李维的结论是不对的。
sData := Format('%x : %s', [Integer(aPtr), sData]);
Memo1.Lines.Add(sData);
...
end;
{ ======================================================== }
问题三:
书中的论述是这样的:
{ ======================================================== }
现在让进行一个实验,看看VMT表格建立的时机。
procedure TForm1.Button4Click(Sender: TObject);
var
aPnl : TPanel;
begin
aClass := aPnl.ClassType;
sClassName := 'TPanel';
ShowVMTContent(aClass);
aPnl := TPanel.Create(Self);
aClass := aPnl.ClassType;
sClassName := 'TPanel';
ShowVMTContent(aClass);
FreeAndNil(aPnl);
end;
上面的程序代码首先声明了一个区域 TPanel 变量 aPnl,接着在还未实际建立 TPanel 对象之前我们藉由 aPnl 显示 VMT 的内容,得到的结果应该是无意义的内容。然而一旦当 TPanel 对象实际在内存中建立之后就可以取得 TPanel 的 VMT 中的内容。我们应该可以推知 VMT 应该是在第一个类对象被建立时才会建立完整的 VMT 内容。
// 我个人认为,李维的这个结论也是错误的。
// 因为当还未实际建立 TPanel 对象时,aPnl 并没有指向一个实际的 TPanel 对象,因此 aPnl 更不可能跟 TPanel 的 VMT 有关联。但是这并不能证明 TPanel 的 VMT 就没有建立。实际上,我们可以在没有建立任何 TPanel 对象时,调用 TPanel.ClassName,而且该函数能够返回正确的值 'TPanel',而 ClassName 就是从 VMT 中获得的。我想这也能够说明,在第一个类对象被建立时,VMT 已经建立起来了。
很钦佩reallike的细致。。。。。。。