带非虚析构函数的基类怎么样?

How about a base class with a non-virtual destructor?

本文关键字:基类 怎么样 析构函数      更新时间:2023-10-16

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

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

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删除

在第一个备选项(删除对象)中,如果是静态类型的操作数与其动态类型不同时,其静态类型应为a操作数的动态类型和静态类型的基类应有虚析构函数,否则行为未定义。在第二个如果对象为动态类型,则可选择(删除数组)已删除的不同于它的静态类型,行为是未定义的。73)

你也不能使用这样的诡计:

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

…因为只有当目标是多态的(即至少有1个virtual成员,而Base没有),你才能用dynamic_cast投射树。

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

虚拟医生不是基类的必要条件,您当然可以对所有已定义的结果都这样做。而且不需要使用op new之类的

与准则相关的问题案例是,在指向派生类实例的指向base的指针上使用delete。

如果您的设计确保删除不会以这种方式发生,则可以继续执行。尽管正确地记录这一点是一个好主意,这样未来的开发人员就不会急于"修复"这种情况,或者不违反规则。