导航
  • 主页
  • 招聘
  • 语言基础/算法/系统设计
  • 数据库相关
  • 图形处理/多媒体
  • 网络通信/分布式开发
  • VCL组件开发及应用
  • Windows SDK/API
  • 问答

初看<<Inside VCL>>的两个疑惑

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表.

以上仅是自己的一点看法,并不定正确.

书刚看了一点,继续看.
...全文
216 点赞 收藏 52
写回复
52 条回复
切换为时间正序
请发表友善的回复…
发表回复
猛禽 2004-08-01
mark
回复
readersm68 2004-02-02
收藏
回复
月光 2004-01-17
等看了再来发表
回复
sywxy 2004-01-15
老达摩,代码太长了.
回复
xzgyb 2004-01-14
FrameSniper(§恋爱的味道是甜的§):
是啊,好久不见了,还好吧,我也刚看这书不久.
5416:
我确实听不懂,没有办法,
不过看你这张爱说话的嘴,怎么看都不像是搞程序的
算了,我不爱和别人练嘴,我看书去了
结贴了
回复
5416 2004-01-14
‘老和尚’,为什么大家都听懂我说的话,而你听不懂呢?
你这个样子怎么能给小和尚做出榜样呢?
你也要回家补语文?阿弥陀佛,你能看懂经文吗?
回复
forgetter 2004-01-14
我来说句公道话,老达摩的这个例子其实上面5416已经说的很清楚了,可能只是有一点Bug,呵呵,对事不对人
回复
outer2000 2004-01-14
这么热闹啊,我闪
回复
FrameSniper 2004-01-14
楼上的两位不要在别人的技术帖里争吵了

5416是哪里来的棒槌只有他自己清楚!少理为好,典型的傻B(8好意思,又说脏话了),哈哈

老达摩,好久不见了——这个书俺还没买到,我们这里来的太迟了

8过现在对这些东西也不清楚了,学习!
回复
lxpbuaa 2004-01-13
关于procedure TForm1.Button7Click(Sender: TObject);中由

sData := MethodName(aPtr);

推出“如果我们反向调用MethodName却无法取得某一地址的方法名称,这是有点奇怪的”的结论,这是错误的,搂住已经将原因讲了,就是作者在这里实际调用的是Form1.MethodName。这是一个低级错误。作者似乎经常通过一些现象推论一些结论,这就是所谓格物致知吧!对此,我的一点感悟是:格物致知时一定要谨慎。不妨反过来想一下,Borland是否会让MethodAddress和MethodName出现如此不对称的现象,如果作者能不那么自信一些,考虑到此不对称现象应该不会出现,那么就能比较容易的推之是自己的错误,这样,书中自然也可以避免这个错误。
至于接着的一个结论:
“因此我们可以推知MethodName似乎只会对从TComponent继承下来的类的published方法才有作用”,我真的不知道是依据什么证据推得的。猜想可能与“类中没有显式指明作用域的成员,实际属于哪个域”的问题有关。比如:

TForm1 = class(TForm)
procedure Button1Click(Sender: TObject);
private
……
end;

其中,Button1Click到底应该属于哪个区域呢?是private、public还是published抑或其他?我曾经听过作者的一堂课,他讲是private。但实际上并不是这样简单,正确的是:在$M编译指令开启时,属于published区域,否则是public区域。 而在VCL中,$M是在TComponent的父类TPersistent处开启的(可以看Classes单元源代码)。加上其他一些阴差阳错的即时联想,作者轻易作出了上述错误结论。

————————————————————————————————————
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
————————————————————————————————————
回复
5416 2004-01-13
借地方打个广告:
‘今年你拿了多少年终奖?http://expert.csdn.net/Expert/TopicView1.asp?id=2656356’
回复
aiirii 2004-01-13
收藏先, 工作時間無法細看!
回复
lxpbuaa 2004-01-13
1、
“在60页
'因此我们可以推知MethodName似乎只会对从TComponent继承下来的类的published方法才有作用';” 这个结论明显是错误的。其测试代码:
procedure TForm1.Button8Click(Sender: TObject);
var
sData: string;
aPtr: Pointer;
begin
aPtr := Pointer(@Self.OnClick); //注意是取得Form1的点击事件处理方法指针,而此时Form1.OnClick处理方法根本不存在,自然返回空。如果书写了Form1.OnClick处理方法,自然可以正确返回其名字。
sData := MethodName(aPtr);
sData := Format('%x : %s', [Integer(aPtr), sData]);
Memo1.Lines.Add(sData);
end;
2、“我们可以推知VMT应该是在第一个类对象被创建时才会创建完整的VMT内容,原因是属于同一个类的所有对象都是共享一个VMT表格”结论也是错误的,帮助上说清楚了:“ There is exactly one VMT per class (not one per object); distinct class types, no matter how similar, never share a VMT. VMTs are built automatically by the compiler, and are never directly manipulated by a program”。既然和类对应,自然不应该和具体的对象有关,实际上,VMT保存的都是一个类的任意个对象的共性的东西,也不需要依赖于具体的对象信息而存在。

我看过此书第三章电子版,总的感觉是作者有些矫柔造作,一些简单的地方故意分割绕述,反而让人更不明白。比如第三章讲覆盖,按照inherited出现位置的不同,强制划分出“3明治”和“逐漸增加法”等,感觉实在牵强(我将这个意见转告给了此书的技术编辑者,作者回信在书中增加相关注释,不知是否付诸实施)。书的技术编辑基本也是形同虚设,光注重修改一些错别字和文句语法问题了,而需要的技术验证确抛掷一边。
不过任何人的书都难免有错误,读者能有机会讨论清楚也就好了。

————————————————————————————————————
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
————————————————————————————————————
回复
cll007 2004-01-13
没有这本书
学习一下下
回复
5416 2004-01-13
Create会调用一系列的函数和过程:
function _ClassCreate(AClass: TClass; Alloc: Boolean): TObject;
class function NewInstance: TObject;
function _GetMem(Size: Integer): Pointer;
......
回复
lgqTiger 2004-01-13
可惜啊!
我还没有买到这本书。
回复
5416 2004-01-13
李维就XXX一个老太太一样,说话拐弯弯,所有‘湾湾’都这样,说直接点不好吗?如果李维不学‘唐僧’,不‘脱了裤子放屁’,楼主的疑惑就不会疑惑了!
书的内容本身没错,拿那些例子得出一个结论就有点牵强了。
回复
5416 2004-01-13
疑惑1、
对于第一个疑惑,就如楼上所言,MethodName只会返回一个published方法的类的函数
疑惑2、
每个类都是在Create执行时才分配内存地址空间的,不执行Create,当然得不到VMT
回复
12rain 2004-01-13
问题1、
只有象我这样的菜鸟才会去翻帮助?还是我的理解力太差?恕菜鸟不知天高地厚、我怎么感觉是李维说了一大堆废话!

If Address does not point to a published method of the object, MethodName returns an empty string.


回复
xzgyb 2004-01-13
whitetiger8([Einstein]):
呵呵,主要是现在在家呆着,上网不是很方便
所以不敢太多说话,呵
回复
发动态
发帖子
Delphi
创建于2007-08-02

4802

社区成员

Delphi 开发及应用
申请成为版主
社区公告
暂无公告