构造函数、析构函数为虚函数的区别

来源:互联网 发布:三个数据库应用系统 编辑:程序博客网 时间:2024/05/21 09:26

关于C++类析构函数为虚函数时,如果是父类的指针用子类来new,如果发生析构时,析构函数是virtual与不是virtual有什么区别。


一、先看第一种最简单的情况吧,教科书上教的,析构函数不是virtual,正常定义一个子类对象

class student   {   public:       int *m_pInt;       student()       {           m_pInt = new int[10];   //1           memset(m_pInt, 0, 10*4);       }          ~student()       {               //3           delete []m_pInt;       }      };      class GradeOneStue:public student   {   public:       int m_iNum;       GradeOneStue()                 {               //2           m_iNum = 1;       }          ~GradeOneStue()       {               //4           m_iNum = 0;       }   };      int _tmain(int argc, _TCHAR* argv[])   {       GradeOneStue gd;       return 0;   }  

构造函数:先调用父类构造函数,再调用子类构造函数;

再来看看析构时的顺序(教科书上写的是先调用子类的析构函数,在调用父类的,与构造过程相反)  


二、析构函数是virtual,正常定义一个子类对象

析构函数最后还是调用了父类的析构(即使是虚函数)。


三、用一个父类指针去new一个子类对象,析构函数不是virtual,构造过程略过

看到只调用了父类的析构函数,此时子类的析构函数没有被调用,此时子类的析构函数中虽然有调用父类析构函数的代码,但是这里直接调用的是父类的析构函数,所以这是如果子类中析构函数有释放资源的代码,这里会造成这部分资源不被释放,有可能造成内存泄


四、用一个父类指针去new一个子类对象,析构函数是virtual,构造过程略过

由于子类的虚构函数最后会调用父类的析构函数(不管是否为virtual,子类析构函数最后都会调用父类析构函数),所以最终父类的析构函数会得到执行。(这时调用的析构函数相当于pStu->vpTable->析构函数(),这个析构函数是构造时写入的,由于构造时使用子类类型去new,此时虚函数表中析构函数的地址是子类的析构函数地址


最后的结论:

1、无论父类与子类的析构函数是否是virtual,子类的析构函数都会调用父类的析构函数

2、如果父类与子类的析构函数不为virtual,用一个父类指针指向一个用子类类型new的对象,delete时,直接调用父类的析构函数,这是在编译时刻就决定的。如果子类析构函数中有释放资源的代码,这是会发生资源泄漏。

3、如果父类与子类的析构函数是virtual,用一个父类指针指向一个用子类类型new的对象,delete时,这时由于是通过虚函数表调用析构函数,而虚函数表中的地址是构造时写入的,是子类的析构函数的地址,由于结论第一条,所以子类与父类的析构函数都会得到调用,不会发生资源泄漏。



*************************************************************************************************************

补充:为什么构造函数不能用虚函数

如果有这样两个类:
class A {
public:
  A() { a = "A"; f(); }
  virtual ~A() {}

  virtual f() { cout << a << endl; }
private:
  char* a;
};
class B : public A {
public:
  B() { b = "B"; }
  ~B() {}

  f() { cout << b << endl; }
private:
  char* b;
};

构造函数调用顺序是先调用基类构造函数,即: A(), B()
在A()中调用f(),如果按虚函数调用规则,它应该调用B::f(),但此时B还没构造(B()还没有执行),执行B::f()必然是一个错误。所以在构造函数内部执行时,对象还没有完全构造好,不能按虚函数方式进行调用,构造函数本身不能为虚函数也是相同的原因了。




原创粉丝点击