C++ 以多态方式删除对象

C++ 以多态方式删除对象,c++,virtual-destructor,C++,Virtual Destructor,我知道,若基类有一个非虚拟析构函数,那个么在删除optr指针时,只会调用~Base()析构函数。但是我发现,即使没有调用~Derived()析构函数,派生对象占用的内存也被释放了。所以我的问题是,一个对象能在不调用析构函数的情况下被释放吗 如果答案是肯定的,那么如果我的派生类不包含任何动态分配的变量,那么我是否可以使用非虚拟析构函数,这样我就不在乎它是否被调用了?查看此处:查看此处:如果派生类不添加任何成员,您可能不需要虚拟析构函数就可以离开。内存占用将是相同的,并且所有成员都将在基类析构函数中

我知道,若基类有一个非虚拟析构函数,那个么在删除
optr
指针时,只会调用~Base()析构函数。但是我发现,即使没有调用~Derived()析构函数,派生对象占用的内存也被释放了。所以我的问题是,一个对象能在不调用析构函数的情况下被释放吗


如果答案是肯定的,那么如果我的派生类不包含任何动态分配的变量,那么我是否可以使用非虚拟析构函数,这样我就不在乎它是否被调用了?

查看此处:

查看此处:

如果派生类不添加任何成员,您可能不需要虚拟析构函数就可以离开。内存占用将是相同的,并且所有成员都将在基类析构函数中销毁。然而,这并不是标准所保证的,您将任由编译器实现的摆布。

如果派生类不添加任何成员,您可能不需要虚拟析构函数就可以逃脱。内存占用将是相同的,并且所有成员都将在基类析构函数中销毁。然而,标准并不能保证这一点,您将任由编译器实现的摆布。

有两件截然不同的事情:调用对象析构函数和释放内存

标准堆规范不要求在释放内存块时传递内存块大小。也就是说,堆实现应该推断内存块大小本身


因此-。如果派生的不包含必须通过适当方式销毁的额外内容(如堆上分配的内存、文件句柄等),则不需要虚拟析构函数。

有两个不同的功能:调用对象析构函数和释放内存

标准堆规范不要求在释放内存块时传递内存块大小。也就是说,堆实现应该推断内存块大小本身


因此-。如果派生的不包含必须通过适当方式销毁的额外内容(如堆上分配的内存、文件句柄等),则不需要虚拟析构函数。

未定义行为的一点是,有时它似乎可以工作


标准并没有说如果基类析构函数不是虚拟的,你的程序一定会失败,而是说当析构函数是虚拟的时,它必须工作。

关于未定义行为的事情是,有时它似乎工作


标准并没有说如果基类析构函数不是虚的,程序必须失败,它说在析构函数是虚的时它必须工作。

< P>从标准C++的观点来看,答案很简单:结果是未定义的行为,所以得到的是完全不可预测的

我有点不明白你为什么会在乎。如果可以从一个类中删除所有虚拟函数,则每个实例都会变小(通过vtable指针的大小)。但是,将这样的东西用作基类很少有意义——要使用作基类是合理的,基本上需要在基类中至少有一个虚函数,派生类才能重写。一旦有了一个虚拟函数(任何虚拟函数),添加更多基本上是免费的——对象不会因为添加更多虚拟函数而变得更大


直接回答您的问题:是的,可以在不调用析构函数的情况下释放内存。真正的问题是,当C++实现这一问题时,会发生什么(实际上没有答案).P/>从标准C++的观点来看,答案很简单:结果是未定义的行为,所以你得到的完全不可预测的

我有点不明白你为什么会在乎。如果可以从一个类中删除所有虚拟函数,则每个实例都会变小(通过vtable指针的大小)。但是,将这样的东西用作基类很少有意义——要使用作基类是合理的,基本上需要在基类中至少有一个虚函数,派生类才能重写。一旦有了一个虚拟函数(任何虚拟函数),添加更多基本上是免费的——对象不会因为添加更多虚拟函数而变得更大


直接回答您的问题:是的,可以在不调用析构函数的情况下释放内存。真正的问题是当你这样做时会发生什么(这个问题确实没有答案)。

在可能的列表中,还有其他情况,比如派生类型不能定义
运算符delete
。。。(即,如果它有一个,则除非析构函数是虚拟的,否则不会调用它)。我曾在新闻中看到一个小孩不小心用鱼叉刺穿了自己的头部,他根本没有受到任何伤害,所以你可以不用用鱼叉射击自己,但我不建议你这样做…@大卫,我不玩鱼叉,所以我很安全!说真的,我从未使用过
运算符delete
,也从未见过其他人使用它。在可能的列表中,还有其他情况,例如派生类型不能定义
运算符delete
。。。(即,如果它有一个,则除非析构函数是虚拟的,否则不会调用它)。我曾在新闻中看到一个小孩不小心用鱼叉刺穿了自己的头部,他根本没有受到任何伤害,所以你可以不用用鱼叉射击自己,但我不建议你这样做…@大卫,我不玩鱼叉,所以我很安全!说真的,我从未使用过
操作符delete
,我也从未见过其他人使用它。
Base* optr=new Derived();

delete optr;