是否有用于使受保护的析构函数虚拟化?

时间:2012-01-23 10:51:04

标签: c++ inheritance protected virtual-destructor

/*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的析构函数设为虚拟,那么我会得到一个错误,那么将受保护的析构函数设为虚拟的目的是什么?

4 个答案:

答案 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中的BaseBase的派生类派生的任何对象。