虚析构函数问题:为什么要将基类的的析构函数设成虚的?
来源:互联网 发布:无间道傻强是警察知乎 编辑:程序博客网 时间:2024/06/06 00:49
转载自:http://blog.csdn.net/pathuang68/article/details/4156308
某CSDN网友问:
class A
{
public:
~A()
{
cout < <"A::~A" < <endl;
}
};
class B:public A
{
public:
virtual ~B()
{
cout < <"B::~B" < <endl;
}
};
class C:public B
{
public:
~C()
{
cout < <"C::~C" < <endl;
}
};
int main()
{
A *a=new A();
B *b=new B();
C *c=new C();
A *d=new B();
A *e=new C();
B *f=new C();
delete a;
cout < <endl;
delete b;
cout < <endl;
delete c;
cout < <endl;
delete d;
cout < <endl;
delete e;
cout < <endl;
delete f;
cout < <endl;
system("Pause");
}
这段程序运行时有错,当时考的时候题目直接说写出运行结果,我就稀里糊涂得写下来,回来编下发现有错,请教下错在哪,最好告诉我为什么?
玄机逸士回答:
1. 一般来说,如果一个类要被另外一个类继承,而且用其指针指向其子类对象时,如题目中的A* d = new B();(假定A是基类,B是从A继承而来的派生类),那么其(A类)析构函数必须是虚的,否则在delete d时,B类的析构函数将不会被调用,因而会产生内存泄漏和异常;
2. 在构造一个类的对象时,先构造其基类子对象,即调用其基类的构造函数,然后调用本类的构造函数;销毁对象时,先调用本类的析构函数,然后再调用其基类的构造函数;
3. 题目给出的代码是可以编译的,但会出现运行时错误。错误出现在delete d;这一句。为讨论方便,我们不妨将A类和B类改写如下:
class A
{
public:
int a;
~A()
{
cout << "A::~A" << endl;
}
};
class B : public A
{
public:
int b;
virtual ~B()
{
cout << "B::~B" << endl;
}
};
那么A* d = new B();这一句的左边所产生B的对象的内存结构如下:
而A对象的内存结构如下:
可见d只能找到a和A类的析构函数,而无法找到B对象的析构函数,所以当delete d;的时候,B对象所占用的内存就此被泄漏掉了,也从而产生了异常。
如果将A类的析构函数设为虚的,那么A类对象的内存结构将为:
B类对象的内存结构为:
此时通过A* d = new B();,A对象的内存结构中的vfptr,即虚函数表指针,就是B对象的vfptr(B对象的vfptr被bitwise copy,即浅拷贝到A对象的vfptr。如B是从A虚继承而来的,则需要加一个offset,情况要更复杂,见
http://blog.csdn.net/pathuang68/archive/2009/04/24/4105902.aspx),因此,A对象的vfptr所指向的是B对象的虚函数表,而B的析构函数位于书函数表0的位置,因此,这样就可以通过A类对象的指针d,找到B类对象的析构函数,从而在delete d;时,可以销毁B对象,而不会产生内存泄漏和异常。
事实上,该题目只要将A中的析构函数设成虚的,B类中的析构函数前面的virtual关键字不管是否存在,其析构函数也一定是虚的,C类同此道理。因此,得到结论就是,只要能够保证继承关系中最高的基类的析构函数是虚的,那么就不会产生前面所谈及的问题。这就是为什么在想使用多态特性的时候,需要将基类的析构函数设成虚的真正原因。
- 虚析构函数问题:为什么要将基类的的析构函数设成虚的?
- 虚析构函数问题:为什么要将基类的的析构函数设成虚的?
- 虚析构函数问题:为什么要将基类的的析构函数设成虚的?
- 虚析构函数问题:为什么要将基类的的析构函数设成虚的?
- [转]虚析构函数问题:为什么要将基类的的析构函数设成虚的?
- 虚析构函数问题:为什么要将基类的的析构函数设成虚的?
- 为什么要将基类的析构函数声明为虚函数
- 为什么虚析构函数的作用
- 基类的析构函数为什么是虚函数?
- 基类的析构函数为什么是虚函数
- 为什么基类的析构函数是虚函数
- 为什么基类的析构函数是虚函数?
- 为什么基类的析构函数是虚函数?
- 为什么基类的析构函数是虚函数
- 为什么基类的析构函数是虚函数?
- 为什么基类的析构函数是虚函数?
- 基类的析构函数为什么是虚函数?
- 为什么基类的析构函数是虚函数?
- HDR是啥意思?
- ssy JAVA SE 006
- 不在JPA 的 persistence.xml 文件中配置Entity class的解决办法
- ios8在通用设置中文键盘无效的解决方法(中文键盘设置)
- 正则表达式应用
- 虚析构函数问题:为什么要将基类的的析构函数设成虚的?
- 线程池基本概念
- Ubuntu12.04 64位 Andrord 编译环境搭建
- android NDK 系列问题1
- Spark技术内幕:Client,Master和Worker 通信源码解析
- SQL时间格式化
- 黑马程序员——内存管理
- PRC_S_SYS_LOG(2)
- Astra工作室:“我们的游戏在高加索很有名。那是一个对赛车狂爱的地方。”