具有非虚拟析构函数的基类怎么样?

时间:2013-05-31 14:30:37

标签: c++ new-operator destructor

如果我在子类私有中声明“operator new”,我可以使用没有虚析构函数的类作为基类吗?

以下代码是否会导致运行时问题:

class B {
public:
    ~B() { }
};

class D: public B {
private:
    void* operator new(size_t);
}

5 个答案:

答案 0 :(得分:4)

您可以将具有非虚拟析构函数的类用作基类,无论您如何在派生类中重写operator new

如果要销毁的实例属于任何派生类型,则必须确保避免使用delete和指向base的指针,因为这会导致未定义的行为。覆盖派生类中的operator new并不会改变这一事实。

答案 1 :(得分:3)

您仍然可以说Base * p = ::new Derived;,从而造成危险情况。

答案 2 :(得分:2)

这里有一套简单的指南,供你何时应该让你的析构函数虚拟

http://www.parashift.com/c++-faq/virtual-dtors.html

如果您打算阻止构造派生类的对象,那么将构造函数设为私有,而不是new运算符。

答案 3 :(得分:2)

C ++语言不要求基类具有virtual析构函数。因此,对您的问题的直接回答是“是”,您可以拥有一个没有虚拟析构函数的基类。

但是,您无法实例化派生对象,delete是通过基类指针而不调用未定义行为。

class Base
{
};

class Derived
:
  public Base
{
  public:
    std::string mString;
};

Base* p = new Derived;
delete p;

您是delete Base指针,但动态类型*pDerivedBase没有virtual析构函数,所以这会调用UB:

5.3.5 / 3删除

  

在第一个替代(删除对象)中,如果是静态类型的   操作数与其动态类型不同,静态类型应为a   操作数的动态类型的基类和静态类型   有一个虚拟析构函数或行为未定义。在第二   替代(删除数组)如果要对象的动态类型   删除与其静态类型不同,行为未定义.73)

你也不能像这样使用欺骗手段:

Base* p = new Derived;
Derived* d = dynamic_cast <Derived*> (p);
delete d;

...因为如果目标是多态的,你只能使用dynamic_cast抛弃树 - 意思是,至少有一个virtual成员 - Base没有。{{1}}成员。

所以,即使对你的问题的直接回答是“是”,真正的答案是“不要这样做。”

答案 4 :(得分:0)

虚拟dtor不是基类的必要条件,您当然可以使用所有已定义的结果。而且无需使用op new或任何其他内容。

与指南相关的问题是当指向base的指针使用delete时,指向派生的实例。

如果您的设计确保删除永远不会发生,那么您可以继续。尽管正确记录这一点是个好主意,但未来开发人员不要急于“修复”这种情况,或者不要违反规则。