如果子类有虚的析构函数而父类没有,会崩溃,原因是啥?

isarc 2011-04-18 04:04:24
各位高人好,请你们指教一个问题。
class X
{
public:
X(){ cout << "X class constructor" << endl;}
~X(){ cout << "X class deconstructor " << endl;}
protected:
private:
};

class XSon : public X
{
public:
XSon(){ cout << "XSon class constructor" << endl;}
virtual ~XSon()
{
cout << "XSon class deconstructor " << endl;
}
// virtual void Copy( XSon* obj );
protected:
private:
};

int main(int argc, char* argv[])
{
XSon* sonp = new XSon;
delete sonp;

cout << "--------------------" << endl;
X* xp = new X;
delete xp;
cout << "--------------------" << endl;
X* xp2 = new XSon;
delete xp2;//执行到这里崩溃。。。。。。。。。
}
我google之后,没有看到具体的解答,看到人家的一句话,感觉答案是子类的虚函数表被拷贝给了父类造成了崩溃,但是,what,why我都不知道,请大家帮个忙。
谢谢。
...全文
554 19 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
奋斗小青年 2011-04-18
  • 打赏
  • 举报
回复
静态联编与动态联编
pathuang68 2011-04-18
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 isarc 的回复:]

玄机逸士你好,请原谅我没看懂你最后一段话的意思跟我说的父类子类的析构函数搜不是虚的有什么关联。
我的问题是如果父类子类的析构函数都不是虚的,那么子类的析构函数没有被调用(从输出语句看到的),内存难道就不泄露了?
为什么同样泄露,它就不崩溃呢?


我决定把我的家底分都加上,最后50分。
[/Quote]

也会崩溃的:)

内存泄露和程序崩溃没有必然的关系。只不过在这地方碰巧在一起了。

如果X和XSon的析构函数都不是虚的,
X* x = new XSon;
delete x;
只会调用X的析构函数,但程序不会崩溃。

如果X的析构函数不是virtual的,而XSon的析构函数时virtual的,那么:
X* x = new XSon;
delete x;
只会调用X的析构函数,而且程序会崩溃。

Meteor_Code 2011-04-18
  • 打赏
  • 举报
回复
release下毫无问题,vc6测试
pengzhixi 2011-04-18
  • 打赏
  • 举报
回复
再说你将派生类析构函数设为非虚的话,那么即使派生类有空基类优化操作,但是并不会发生指针指向的调整,所以delete是没有任何问题的。解决问题最好的方式就是:将基类析构函数声明为虚函数。
pengzhixi 2011-04-18
  • 打赏
  • 举报
回复 1
详细点说下吧。
你写的那个程序;首先基类大小为1(这个自己去看书),派生类大小为4(vptr)
当你在用基类指针指向new返回的一个派生类对象的时候。这个时候因为基类不含vptr那么编译器会帮我们调整基类指针的指向。指向基类部分,假设原本new返回的地址为0,那么调整之后基类指针指向的地址是4(为什么呢?因为派生类就含有一个vptr,派生类的大小就只有4在派生类对象中,实际的基类部分已经做了空基类优化的操作)很明显这个时候你对基类指针进行delete那么执行的是基类的析构函数。然后再释放指针(问题就出现在这里了,你释放的这个指针包含的地址已经不再是new返回的那个地址了,这个时候就可能破坏堆)。
pengzhixi 2011-04-18
  • 打赏
  • 举报
回复
都不是虚的话,不存在调整指针的指向那么new时和delete时指针所指的地址是一致的。
isarc 2011-04-18
  • 打赏
  • 举报
回复
玄机逸士你好,请原谅我没看懂你最后一段话的意思跟我说的父类子类的析构函数搜不是虚的有什么关联。
我的问题是如果父类子类的析构函数都不是虚的,那么子类的析构函数没有被调用(从输出语句看到的),内存难道就不泄露了?
为什么同样泄露,它就不崩溃呢?


我决定把我的家底分都加上,最后50分。
pengzhixi 2011-04-18
  • 打赏
  • 举报
回复
额 你可以将new返回的指针同时赋给一个派生类的指针和一个基类的指针然后看两个指针保存的地址值是否相同,另外你用sizeof输出两个类型的大小基本上你就知道怎么回事了。
isarc 2011-04-18
  • 打赏
  • 举报
回复
感谢5楼,不过面对我上面的问题,我还是不理解你的回答,能否详细些?


子类对象 -->[0X12345678父类内存大小0X123459999+子类内存大小]
父类根据指针类型决定这个指针式[0X12345678父类内存大小0X123459999]
怎么会转换指针位置?
pathuang68 2011-04-18
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 isarc 的回复:]

感谢楼上的答复。
你的专栏里有一句话:
可见d只能找到a和A类的析构函数,而无法找到B对象的析构函数,所以当delete d;的时候,B对象所占用的内存就此被泄漏掉了,也从而产生了异常。

我想问,如果我让子类的析构函数不为virtual,这时子类的析构函数不会被调用,程序不会崩溃,同样内存泄露,为啥这个不崩溃?
[/Quote]
请看4楼推荐的那篇文章中的最后一段话。
pathuang68 2011-04-18
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 isarc 的回复:]

感谢楼上的答复。
你的专栏里有一句话:
可见d只能找到a和A类的析构函数,而无法找到B对象的析构函数,所以当delete d;的时候,B对象所占用的内存就此被泄漏掉了,也从而产生了异常。

我想问,如果我让子类的析构函数不为virtual,这时子类的析构函数不会被调用,程序不会崩溃,同样内存泄露,为啥这个不崩溃?
[/Quote]

只要父类的析构函数是virtual的,那么子类的析构函数就一定是virutal的(不管你前面有没有加virutal关键字)
oldmtn 2011-04-18
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 pengzhixi 的回复:]

X* xp2 = new XSon;
问题在于你基类不含有vptr,那么意味着这句在调整xp2的指向的时候修改了new返回的原始地址。这样在析构的时候 1.执行的是基类的析构函数。2. new返回的原始地址和你析构时候的地址已经不一致了。所以在释放内存的时候就出现错误
[/Quote]

up~~
isarc 2011-04-18
  • 打赏
  • 举报
回复
感谢楼上的答复。
你的专栏里有一句话:
可见d只能找到a和A类的析构函数,而无法找到B对象的析构函数,所以当delete d;的时候,B对象所占用的内存就此被泄漏掉了,也从而产生了异常。

我想问,如果我让子类的析构函数不为virtual,这时子类的析构函数不会被调用,程序不会崩溃,同样内存泄露,为啥这个不崩溃?
pengzhixi 2011-04-18
  • 打赏
  • 举报
回复
X* xp2 = new XSon;
问题在于你基类不含有vptr,那么意味着这句在调整xp2的指向的时候修改了new返回的原始地址。这样在析构的时候 1.执行的是基类的析构函数。2. new返回的原始地址和你析构时候的地址已经不一致了。所以在释放内存的时候就出现错误
pathuang68 2011-04-18
  • 打赏
  • 举报
回复
如果一个类要作为基类,那么其析构函数必须是虚的,否则使用多态的时候,其派生类对象不会被析构。

道理请见:
虚析构函数问题:为什么要将基类的的析构函数设成虚的?
isarc 2011-04-18
  • 打赏
  • 举报
回复
楼上高人能否简单给讲解一下,你说的那本数我看过,不是很懂。删除的时候,怎么使用虚表的?
luciferisnotsatan 2011-04-18
  • 打赏
  • 举报
回复
知道 “虚函数表”是什么吗
如果不知道,而你又想知道 what,why,建议找本Inside c++ object model看看
这里涉及的知识比较多
quwei197874 2011-04-18
  • 打赏
  • 举报
回复
不会析构父类,基类必须要有虚析构函数,否则必出错.

65,187

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧