/*Child is inherited from Parent*/
class Parent {
public:
Parent () //Constructor
{
cout << "\n Parent constructor called\n" << endl;
}
protected:
~Parent() //Dtor
{
cout << "\n Parent destructor called\n" << endl;
}
};
class Child : public Parent
{
public:
Child () //Ctor
{
cout << "\nChild constructor called\n" << endl;
}
~Child() //dtor
{
cout << "\nChild destructor called\n" << endl;
}
};
int main ()
{
Parent * p2 = new Child;
delete p2;
return 0;
}
如果我将Parent
的析构函数设为虚拟,那么我会得到一个错误,那么将受保护的析构函数设为虚拟的目的是什么?
答案 0 :(得分:18)
举一个例子:假设您有一个实现引用计数的基类。你有一个addRef
和一个release
方法,你希望你的对象被销毁,如果(和只 if)内部计数器通过调用{{1 }}。
所以,首先你要保护你的析构函数(因为你只想从release
中删除对象)。
如果您计划从您的类派生,您还希望将析构函数设置为虚拟,因为每当您想要通过指向基类的指针销毁子对象时,您都需要一个虚拟析构函数(感谢@sharptooth提示。 ..)
答案 1 :(得分:5)
是的,如果您打算在delete this
成员函数中执行class Parent
,这在COM对象中实现IUnknown::Release()
时非常常见。
答案 2 :(得分:5)
an entry in the C++ Core Guidelines专用于此特定主题:
C.35:基类析构函数应该是公共的和虚拟的,或者 受保护且非虚拟
原因,以防止发生未定义的行为。如果破坏者是公开的, 然后调用代码可以尝试破坏派生的类对象 通过基类指针,如果基 类的析构函数是非虚拟的。如果析构函数受到保护, 那么调用代码无法通过基类指针和 析构函数不需要是虚拟的;它确实需要受到保护, 不是私有的,以便派生的析构函数可以调用它。一般来说, 基类的作者不知道要采取的适当措施 在毁灭之后完成。
因此,如果析构函数受到保护,则不需要是虚拟的。但是,有一个例外:
例外我们可以想象一种情况,您可能想要一个受保护的虚拟机 析构函数:当对象具有派生类型(且仅属于此类类型)时 应该允许通过一个销毁另一个物体(而不是本身) 指向基础的指针。不过,在实践中我们还没有看到这样的情况。
因此,总而言之,实际上,受保护的析构函数不需要是虚拟的。
答案 3 :(得分:4)
protected: Base::~Base();
至少应该是虚拟的,如果您(计划)删除Base
中的Base
或Base
的派生类派生的任何对象。