本人一直对构造函数有个疑惑,为什么构造函数在TObject中不像析构函数那样是虚函数?对实际对象构造的实现不是要在TObject的继承类来实现吗?还有我看到TComponent中又把构造函数声明为虚函数,现在我真是有点迷惑了,什么时候构造函数应该为虚函数?什么时候不应该?为什么?还有像TComponent这样,祖先类构造函数不是虚函数,自己又把构造函数声明为虚函数,在语义上到底是什么意思? 

解决方案 »

  1.   

    楼上的老大没有看清楚,我的意思是什么时候我们应该把构造函数声明为虚函数?什么时候应该声明成一般函数?为什么在TObject中构造函数不是虚函数,而在TComponent中构造函数是虚函数?为什么不把TObject声明为虚函数,在TComponent中override?
      

  2.   

    我这样想的,TObject类是根,它的非虚的 Create 函数可以保证任何对象都被正确的构造,任何对象调用 Create 后都会执行到 TObject.Free,保证了对象被正确的构造 ; 它也有一个非虚的 Free 函数,同样的道理 ;除了TObject 外的父类的构造都可以为虚以便子类覆盖 ;
      

  3.   

    static和virtual的区别。先看一个声明:type
      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就不能够正确释放对象。以上纯属个人见解,仅供参考,如果有误,不要扁我。
      

  4.   

    请问dbExpress,下面的代码有具体有什么意义?TObject与TComponent就是这样的关系。interfacetype  TAncestor = class
      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,不需我们去显示的调用。当然这只是我自己的想法,不知道是否正确?
      

  5.   

    inherited Proc调用的是TDescendant1.Proc,TAncestor.Proc被隐藏了。
    但又有什么问题呢?不太懂你的"编译器会自动去执行TObject.Create"这一句。
    实际上,constructor 函数可以理解为两个函数,一个是对象空间分配函数,constructor关键字指示编译器加插必要的代码来分配对象需要的空间。另一个是Create的实际函数体,用来Initialize Instance,关于这些,你可以看看翅旁大佬的帖子
    http://expert.csdn.net/Expert/topic/1492/1492518.xml?temp=.5634119