当使用基类指针指向派生类对象时,没有问题,但是要是想把这个基类指针给删掉,这时候问题就来了,例如下面这个例子:
class BaseClass {
private:
char *name;
public:
BaseClass(int size) {
name = new char[size];
for (int i = 0; i 'a';
}
// 基类的析构函数
~BaseClass() { delete name; }
};
class DeriveClass : public BaseClass {
private:
char *count;
public:
DeriveClass(int size) : BaseClass(size) {
count = new char[size];
for (int i = 0; i 'b';
}
// 派生类的析构函数
~DeriveClass() { delete count; }
};
int main() {
// 多态用法,基类指针指向派生类对象,没毛病
BaseClass *obj = new DeriveClass(16);
// 删除基类指针,出现了问题!
delete obj;
return 0;
}
上面的程序乍一看看不出个毛病来,现在对 BaseClass *obj = new DeriveClass(16);
设置断点,进行单步调试,可以观察到构造函数过程是:
new DeriveClass(16)
|
BaseClass(16)
|
DeriveClass(16)
|
end
这个顺序完全正确,先构造基类再构造派生类嘛,执行完后,内存状态是这样的:
内存状态表示
可以得知操作系统给这两个对象中的成员分配内存到了 name : 0x1061980
和 count : 0x10619c0
。
那么执行 delete obj;
时,顺序是这样的:
delete obj
|
~BaseClass()
|
end
从上面可以看出来,竟然只执行了基类的析构函数,而没有执行派生类的析构函数,那么这时的内存表示是怎么样的?见下图:
内存状态表示
由此可见,在不经意间,就造成了内存泄漏问题,那么该如何解决这个问题呢?
很简单,只需要把基类的析构函数声明为 virtual
就可以了,这样强制去执行子类的析构函数。
不过,这样还是有两种结果,例如下面是一种结果:
class BaseClass {
// 其他都一样
virtual ~BaseClass() { delete name; }
};
class DeriveClass : public BaseClass {
// 其他都一样
~DeriveClass() override { delete count; }
};
这个时候,是先执行的派生类析构函数,再执行基类析构函数。
另一种结果是:
class BaseClass {
virtual ~BaseClass() { delete name; }
};
class DeriveClass : public BaseClass {
// 删掉了自己的析构函数
};
这个情况下,才是先执行基类析构函数,再执行派生类析构函数。