构造函数与虚析构函数

来源:互联网 发布:ubuntu 安装openjdk 8 编辑:程序博客网 时间:2024/05/21 06:39
1. 构造函数
         因为在派生类中构造函数是不能继承的,也没有重定义的必要。在构造函数中调用虚函数将破坏动态绑定逻辑。下面的例子说明了这样动态绑定逻辑。
例:       
  #include<iostream.h>
  class base
   {
      protected:
      int x;
      public:
      base (int m)
       {
         x=m+1;
         print( );
       }
      virtual void print( )
       {
         cout<<”The virtual function  in base is called!”<<endl;
        cout<<x<<endl;
    }
};
class derive: public base
  {
     private:
     int y;
     public:
    derive (int m): base(m)
      {
        y=m;
        print( );
      }
virtual void print( )
    {
      cout<<”The virtual function in derive is called!”<<endl;
      cout<<y<<endl;
    }
 };
 void main( )
    {
      derive  obj(10);
    }
程序的输出结果为:
         The virtual function in base is called!
         11
         The virtual function in derive is called!
         10
         程序从创建派生类的对象开始执行,在执行中,先要调用基类的构造函数。此时派生类的创建过程尚未完成,只能按静态绑定调用基类的虚函数,无法实现预期的多态逻辑。
请记住:
          在构造和析构期间不要调用virtual 函数,因为这类调用从不下降至derived class(比起当前执行构造函数和析构函数的那层)。       
        如果在构造函数或析构函数中调用虚函数,则运行的是为构造函数或析构函数自身类型定义的版本。可以理解为:在base class 构造期间, virtual 函数不是virtual 函数。

2.虚析构函数

析构函数可以通过virtual修饰而声明为虚析构函数。虚析构函数与一般虚函数的不同之处在于:
      (1)覆盖虚析构函数的重定义函数就是派生类的析构函数,不要求同名;
      (2)虚析构函数由系统自动调用;
      (3)一个虚析构函数的版本被调用后,接着就要调用被它覆盖的基类版本,依次类推,直到调用了派生序列的根类的析构函数版本为止。
    

    为什么析构函数为虚?

     在处理继承层次中的对象时,指针的静态类型可能与被删除对象的动态类型不同。因此基类中的析构函数必须为虚函数(虚函数特性会被继承,派生类的析构函数也是虚的)。

Base *pBase = new Derived;

delete pBase;

如果Base的析构函数不为虚,删除指针时只会执行Base的析构函数,造成内存泄漏;反之,则先析构Derived,再析构Base。

例:

#include<iostream.h>
 class base
  {
    public:
    virtual void say( )
     {
       cout<<”I am base.”<<endl;
     }
    ~base( )
     {
       cout<<”Delete object of
              base”<<endl;
     }
  };
class derived:public base
 {
   public:
   virtual void say( )
    {
      cout<<”I am derived”<<endl;
    }
  ~derived( )
    {
      cout<<”Delete object of derived”<<endl;
    };
void main( )
  {
    base *p1=new derived;
    p1->say( );
    delete p1;
  }
程序的输出结果为:
         I am derived
         Delete object of derived
        显然,p1->say( )语句正确地动态绑定了派生类中的重载代码,delete p1语句也正确地释放了为p1分配的内存空间。 但是,base*p1=new derived 语句执行时,先创建了一个指向base类对象的指针p1,然后又创建了一个derived类的动态对象,最后再让p1指向derived的对象。所以delete p1执行时应调用base和derived两个类的构造函数。
       由于该程序定义的多态性中没有将析构函数用virtual关键字说明,delete p1的执行是不正确的。析构函数加上virtual关键字说明,重新运行程序将得到以下正确结果:
         I am derived
         Delete object of derived
         Delete object of base

请记住:
• polymorphic (带多态性质的) base classes 应该声明一个virtual 析构函数。如果class 带有任何virtual 函数,它就应该拥有一个virtual 析构函数。
• Classes 的设计目的如果不是作为base classes 使用,或不是为了具备多态性(polymorphically) ,就不该声明virtual 析构函数。






原创粉丝点击