需要虚析构函数的原因:
首先看一下这段代码:
#include <iostream>
using namespace std;
class A {
private:
int *a;
public:
A() { a = new int; cout << "A::A() is called.\n"; }
~A() { delete a; cout << "A::~A() is called.\n"; }
void print() { cout << "A::print() is called.\n"; }
};
class B : public A {
private:
int *b;
public:
B() { b = new int; cout << "B::B() is called.\n"; }
~B() { delete b; cout << "B::~B() is called.\n"; }
void print() { cout << "B::print() is called.\n"; }
};
int main() {
A * p = new B();
delete p;
return 0;
}
说明:
- 可以将子类指针(或引用)赋值给父类指针(或引用)
- 在构造子类对象时,会先构造父类对象,再构造对应的子类对象部分
- 在
new
新空间时,之后必须进行delete
,否则会造成内存泄漏
代码运行结果:
A::A() is called.
B::B() is called.
A::~A() is called.
可以发现仅对B进行了构造,而没有进行析构,因此可能会造成内存泄漏。为了避免这一问题的发生,就需要引出一个新的知识点——虚析构函数。
虚析构函数
析构函数
与虚函数
我们已经熟悉了,那么如何实现虚析构函数呢?顾名思义,只要把虚函数与虚构函数结合起来就行了。例如:
class A {
public:
A(); //构造函数
virtual ~A(); //虚析构函数
virtual void print(); //虚函数
};
可见,只要在原来的析构函数声明前加上virtual
关键字就形成了虚析构函数。由此可以修改代码为:
#include <iostream>
using namespace std;
class A {
private:
int *a;
public:
A() { a = new int; cout << "A::A() is called.\n"; }
virtual ~A() { delete a; cout << "A::~A() is called.\n"; } //添加virtual关键字,形成虚析构函数
void print() { cout << "A::print() is called.\n"; }
};
class B : public A {
private:
int *b;
public:
B( int *t ) { b = new int; cout << "B::B() is called.\n"; }
~B() { delete b; cout << "B::~B() is called.\n"; }
void print() { cout << "B::print() is called.\n"; }
};
int main() {
int x = 1;
A * p = new B( &x );
delete p;
return 0;
}
运行结果:
A::A() is called.
B::B() is called.
B::~B() is called.
A::~A() is called.
此时各个对象都会调用析构函数,问题也就解决了。
仅在基类声明为虚析构函数原因:
同普通虚函数一样,它的实现也需要维护一个虚函数表,在此基础上来根据对象类型来选择使用哪个虚构函数。以上面代码为例,由于p实际指向的是B类型的对象,又由于在基类声明了虚析构函数,因此会根据类型选择调用B的析构函数,同时由于在析构派生类时也会自动调用基类的析构函数,所以最终所有的对象都会被析构。
(并不是所有c++类都应该将析构函数设置为virtual。只有具有virtual函数的多态基类(或者其它想当base class的类)才应该将析构函数设置为virtual,对于普通的类则无必要。因为虚函数的实现要求对象携带额外信息,也就是维护一个指向虚函数表的指针vptr(virtual table pointer),vptr指向虚函数表vtbl(virtual table)。当调用一个对象的虚函数时,就会通过vptr找到vtbl,在vtbl中寻找正确的函数指针调用。由于vptr的加入,导致对象大小增加。所以对于非多态基类,没必要将析构函数声明为virtual以带来额外负担。 ——引用自https://www.cnblogs.com/zhuyf87/archive/2013/03/12/2955058.html)