虚析构函数——基类虚构函数前不加virtual,派生类析构函数前加virtual,运行时

qq_42443978 2018-06-12 04:24:59
如标题 运行时会出现图片中的对话框,有没有大佬帮我解释一下是为什么。
代码如下:
class Base
{
public:
~Base(){cout<<"delete Base class"<<endl;}
};

class Derived:public Base
{
public:
Derived()
{
p = new int[100];
}
virtual ~Derived()
{
delete[] p;
cout<<"delete new p"<<endl;
cout<<"delete Derived class"<<endl;
}

private:
int *p;
};

void fun(Base *b)
{
delete b;

}

int main()
{
Base *B=new Derived();
fun(B);
return 0;
}
...全文
1064 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
PDD123 2018-07-12
  • 打赏
  • 举报
回复
有虚函数的时候,类的前四个字节是存储虚函数列表的地址(指向函数指针的指针)。
调用虚函数的时候,是通过虚函数列表以及虚函数在列表中的偏移量来计算虚函数的地址,然后调用。
虚析构函数也如此。
而在析构函数不是虚的时候,调用析构函数,就是直接调用析构函数的地址了。
fun函数,认的是Base对象,所以析构delete b的时候,就直接调用了Base::~Base()

我曾经忘了把析构函数弄成虚的,结果内存泄漏很严重,但是没有崩溃。用的是VC++。
书香门第 2018-06-15
  • 打赏
  • 举报
回复
其实只要你在被继承类中加上任意一个virtual函数都不会有地址访问错误了,虽然逻辑上仍然是不对的,就是子类的析构函数不会被调用。如果你跟一下汇编代码的话你会发现父类析构部分的执行没有错误,但是删除父类的时候出错了,也就是说父类的地址指针算错了。所以我仅仅是推测编译器是按照你的父类中有虚拟指针表来计算地址算错了。当然其实这跟什么都没说一样,还是不知道vs实现的细节。但是代码的问题很确定,其实我觉得也不要纠结编译器实现细节了。
棉猴 2018-06-13
  • 打赏
  • 举报
回复
先说正常情况,如果在基类的析构函数中上virtual,则先调用派生类的析构函数,再调用基类的析构函数。 如果基类和派生类的析构函数中都不加virtual,则调用基类的析构函数。 如果按照你说的这样,在派生类的析构函数中加virtual,而在基类的析构函数中不加virtual,就会报错。估计应该跟虚函数表有关系,因为正常情况下,派生类的VTABLE与基类的VTABLE有相同的函数排列顺序,同名的虚函数被放在两个数组的相同位置。但是现在派生类的VTABLE中有析构函数地址,而基类的VTABLE中没有析构函数地址。可能是由于虚函数表的不对应导致了错误。
qq_42443978 2018-06-12
  • 打赏
  • 举报
回复
引用 2 楼 qq_36751214 的回复:
在ubuntu 5.4.0下,程序没有崩溃,仅仅输出了,基类的析构,存在内存泄漏。
如果是内存泄漏的原因的话那基类和派生类的析构函数前都不加virtual应该也会有这个问题,可是我之前尝试的时候并没有,只是调用了基类的析构函数,存在内存泄漏,但运行时没有出现这个对话框; 我用的是vc++6.0 我在尝试普通的函数时发现基类的函数前不加virtual而派生类的对应函数前加virtual没有引起这个问题,只是单纯地调用了基类的函数而已,但析构函数就会有这个问题,是因为派生类的析构函数会调用基类的析构函数吗?但我尝试了用普通函数进行实验在基类的函数前不加virtual而派生类的前加virtual并在该函数里调用基类的对应函数,是没有发生这种问题的 所以我就不知道到底为什么编译器会做这种处理了
宁南学者 2018-06-12
  • 打赏
  • 举报
回复
在ubuntu 5.4.0下,程序没有崩溃,仅仅输出了,基类的析构,存在内存泄漏。
宁南学者 2018-06-12
  • 打赏
  • 举报
回复
不同编译器,对这个情况处理可能不同,有的编译器,不会崩溃程序,但是存在内存泄漏。

33,311

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 新手乐园
社区管理员
  • 新手乐园社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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