说明

对于基类继承类的构造函数和析构函数的执行顺序为:

  • 构造函数

    1. 基类的构造函数
    2. 继承类的构造函数
  • 析构函数

    1. 继承类的析构函数
    2. 基类的析构函数

为什么需要将基类的析构函数指定为 virtual 呢?

因为当用基类的指针指向一个继承类对象时,在 delete 基类指针时,如果不将析构函数指定为 virtual,则实际只有基类的析构函数会被调用,而继承类的析构函数不会被执行。所以当继承类中有资源需要在析构函数中释放时,会造成内存泄露等。

带有 virtual 的基类析构函数实例

#include <iostream>

class Something {
public:
Something() { std::cout << "2"; }
virtual ~Something() { std::cout << "2"; }
};

class Base {
public:
Base() { std::cout << "1"; }
virtual ~Base() { std::cout << "1"; }
};

class Derived : public Base {
public:
Derived() { std::cout << "3"; }
~Derived() override { std::cout << "3"; }

private:
Something m_dataMember;
};

int main() {
Base *ptr{new Derived{}};
delete ptr;
}

此时程序的输出为

123321

输出结果表示先执行基类的构造函数,然后执行继承类成员的初始化,然后执行继承类的构造函数;接着执行继承类的析构函数,继承类成员的释放,基类的析构函数

不带 virtual 的基类析构函数实例

#include <iostream>

class Something {
public:
Something() { std::cout << "2"; }
virtual ~Something() { std::cout << "2"; }
};

class Base {
public:
Base() { std::cout << "1"; }
~Base() { std::cout << "1"; }
};

class Derived : public Base {
public:
Derived() { std::cout << "3"; }
~Derived() { std::cout << "3"; }

private:
Something m_dataMember;
};

int main() {
Base *ptr{new Derived{}};
delete ptr;
}

此时程序的输出为

1231

输出结果表示先执行基类的构造函数,然后执行继承类成员的初始化,然后执行继承类的构造函数;接着执行基类的析构函数