如果我在子类私有中声明“operator new”,我可以使用没有虚析构函数的类作为基类吗?
以下代码是否会导致运行时问题:
class B {
public:
~B() { }
};
class D: public B {
private:
void* operator new(size_t);
}
答案 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
指针,但动态类型*p
为Derived
而Base
没有virtual
析构函数,所以这会调用UB:
在第一个替代(删除对象)中,如果是静态类型的 操作数与其动态类型不同,静态类型应为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时,指向派生的实例。
如果您的设计确保删除永远不会发生,那么您可以继续。尽管正确记录这一点是个好主意,但未来开发人员不要急于“修复”这种情况,或者不要违反规则。