繁体   English   中英

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

[英]How about a base class with a non-virtual destructor?

如果我在子类中声明了“新的运算符”,是否可以将没有虚拟析构函数的类用作基类?

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

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

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

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

您必须确保避免的一件事是,如果要销毁的实例属于任何派生类型,则使用带有指向基础的指针的delete ,因为这会导致未定义的行为 在派生类中重写operator new不会改变这一事实。

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

这是一组简单的准则,适用于何时应将析构函数虚拟化

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

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

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

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

class Base
{
};

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

Base* p = new Derived;
delete p;

您正在delete Base指针,但是*p的动态类型是Derived并且Base没有virtual析构函数,因此将调用UB:

5.3.5 / 3删除

在第一个替代方案(删除对象)中,如果操作数的静态类型不同于其动态类型,则静态类型应为操作数动态类型的基类,并且静态类型应具有虚拟析构函数或行为未定义。 在第二种选择(删除数组)中,如果要删除的对象的动态类型不同于其静态类型,则行为是不确定的(73)。

您也不能采用这种欺骗手段:

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

...因为仅当目标是多态的(即,至少具有1个virtual成员)时,才能使用dynamic_cast树,而Base没有。

因此,即使您问题的直接答案是“是”, 真正的答案是“不要那样做”。

虚拟dtor不是基类的要求,您当然可以对所有定义的结果进行操作。 无需使用op new或任何东西。

与准则有关的问题案例是在指向指向派生实例的基础的指针上使用delete时。

如果您的设计确保删除绝不会那样做,则可以继续进行。 尽管适当地记录下来是一个好主意,以便将来的开发人员不要急于“解决”这种情况或不违反规则。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM