菜鸟笔记
提升您的技术认知

构造函数、析构函数和虚函数的关系-ag真人游戏

首先明确两点

  1. 构造函数不可能定义为虚函数
    虚函数的目的是通过父类引用或者指针调用子类的成员函数。而构造函数的目的是创建对象。创建子类对象时,将调用子类的构造函数,而不是父类的构造函数。子类的构造函数将使用父类的一个构造函数。这种顺序不同于继承机制。因此,子类不继承父类的构造函数,所以将类的构造函数声明为虚函数没有意义。这个如果不能理解,记住就好了。
  2. 父类的析构函数应该是虚函数

关于第二点,举个例子
a是父类,b是a的子类,在b中还添加了一个char* name成员,name指向一块由new申请的内存。当b类的对象被销毁是,必然会调用~b()析构函数来释放内存。请看下面代码:

a* a = new b;
...
delete a;     //此时调用哪个析构函数,~a()还是~b();

如果,a 的析构函数没有声明为虚函数,那么delete a使用默认的静态联编,也就是调用a的析构函数~a();这将会释放掉b类中a部分指向的内存,但是不会释放新的类成员指向的内存,也就是b的name成员指向的内存块,这样就造成内存泄漏的问题。但是如果a的析构函数声明为虚函数,那么b的虚函数表中会把指向a的析构函数的指针位置改为指向b的析构函数。此时调用delete a就会调用b的析构函数,释放掉由b指向的内存,然后调用a的析构函数,释放由a指向的内存。
空口无凭,来个例子看看再说。

例1

#include
using namespace std;
class a {
    public:
        ~a() {
            cout<<"a::~a()"<

这段代码执行结果:

a::~a()

可见仅仅执行了a的析构函数,释放掉了a指向的内存,但是b指向的内存没有被释放掉。
我们把a的析构函数声明为虚函数

virtual ~a() {
            cout<<"a::~a()"<

再次执行,结果如下:

b::~b()
a::~a()

程序先调用子类的析构函数,释放掉b指向的内存,然后调用父类的析构函数,释放掉a指向的内存。

网站地图