本人一直对构造函数有个疑惑,为什么构造函数在TObject中不像析构函数那样是虚函数?对实际对象构造的实现不是要在TObject的继承类来实现吗?还有我看到TComponent中又把构造函数声明为虚函数,现在我真是有点迷惑了,什么时候构造函数应该为虚函数?什么时候不应该?为什么?还有像TComponent这样,祖先类构造函数不是虚函数,自己又把构造函数声明为虚函数,在语义上到底是什么意思?
解决方案 »
- 如果一个外部程序是VC或者PCB写的,用delphi能给它发送sendmessage消息嘛?
- Delphi 存储过程 Execproc Stack overflow
- Delphi调用Tuxedo问题,用fget32函数取blob数据存放在pchar类型变量里,blob数据中零终止符后的字符串被自动截断
- dcom连接,客户机总是提示:接口不支持!
- 为什么不能执行?
- vb中有一个函数asc,delphi中有类似的函数吗?
- 请问各位高手,如何把一个报表数据(记录集)的数据送到传真,Email 等
- 谁能帮我翻译一下?有分!
- 请关注,一定给分!!!
- 好象是tWebBrowser控件的bug,有在tWebBrowser中不能回车以及copy的问题吗?
- 关于DBMemo控件的问题
- dephi跳转指令是什么的??比如掉转到指定位置??
TAncestor = class(TObject)
public
procedure StaticProc;
procedure VirtualProc; virtual;
end;
TDescendant = class(TAncestor)
public
procedure StaticProc;
procedure VirtualProc; override;
end;var
B: TAncestor;
如果我们接着执行这样的代码。
B := TDescendant.Create;
这时,B是一个TDescendant的实例,当调用
B.StaticProc;
那么实际调用的TAncestor.StaticProc,虽然Self是TDescendant的实例。当这样调用
TDescendant(B).StaticProc;
时,编译器才理解为你要调用的是TDescendant.StaticProc;在考察一下virtual,
同上面的声明:
var
B: TAncestor; B := TDescendant.Create;
B.VirtualProc;那么对于B.VirtualProc语句,编译器生成的代码类似于:ActualClassOfObject := Pointer(B^);
ProcPtrToCall := ActualClassOfObject + Offset(VirtualProc);
Self := B;
Call(ProcPtrToCall);由于B实例的实际的Class是TDescendant,所以执行时
ActualClassOfObject = TDescendant;
所以,
ProcPtrToCall := TDescendant.VirtualProc;回过头来看为什么TComponent的Create函数要声明为virtual。
举个常见的例子,Delphi的对象设计器。当你在Component Palette选取一个组件类,然后
在设计Form上创建该类的对象。假设这个代码是:type
TComponentClass = class of TComponent;var
ClassOfComponentToCreate: TComponentClass;
Component: TComponent;
begin
ClassOfComponentToCreate := GetClass(aUserSelectedComponentClassName);
Component := ClassOfComponentToCreate.Create(DesignerForm); //statement 1
Component.Parent := DesignerForm;
...
end;如果TComponent.Create声明为static,那么statement1实际调用的是TComponent.Create,
显然不能得到用户所希望的组件;但是如果TComponent.Create声明为virtual,那么
statement1实际调用的是用户所选择的组件的类的Create方法。这应该是TComponent.Create声明为virtual的原因之一。
如果你的组件类是支持可视设计的,那么你就不要更改TComponent.Create的方法的声明,
包括参数声明。至于Destory为什么要声明为virtual,道理是一样的,声明一个对象为TObject类,实际创建时可能是一个TStringList或者其他的类,如果不用virtual,那么Destroy就不能够正确释放对象。以上纯属个人见解,仅供参考,如果有误,不要扁我。
public
procedure Proc;
end; TDescendant1 = class(TAncestor)
public
procedure Proc; virtual;
end; TDescendant2 = class(TDescendant1)
public
procedure Proc; override;
end;implementation procedure TDescendant2.Proc;
inherited Proc;
...... //其他代码
end;其中inherited Proc; 这句调用的是TDescendant1.Proc吗?那TAncestor.Proc不是被隐藏了吗?其实我认为wjlsmail的想法是合理的,就是把TObject特殊出来单独看待,认为编译器会自动去执行TObject.Create,不需我们去显示的调用。当然这只是我自己的想法,不知道是否正确?
但又有什么问题呢?不太懂你的"编译器会自动去执行TObject.Create"这一句。
实际上,constructor 函数可以理解为两个函数,一个是对象空间分配函数,constructor关键字指示编译器加插必要的代码来分配对象需要的空间。另一个是Create的实际函数体,用来Initialize Instance,关于这些,你可以看看翅旁大佬的帖子
http://expert.csdn.net/Expert/topic/1492/1492518.xml?temp=.5634119