12
/*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

4 回答 4

20

举一个例子:假设你有一个实现引用计数的基类。如果(且addRef)内部计数器通过调用.releaserelease

因此,首先您希望您的析构函数受到保护(因为您只想从内部销毁对象release)。

如果您打算从您的类派生,您还希望您的析构函数是虚拟的,因为每当您想通过指向基类的指针销毁子对象时都需要一个虚拟析构函数(感谢@sharptooth 的提示......)

于 2012-01-23T11:12:11.163 回答
12

C++ 核心指南中有一个专门针对这个特定主题的条目:

C.35: 基类析构函数应该是公共的和虚拟的,或者是受保护的和非虚拟的

原因防止未定义的行为。如果析构函数是公共的,则调用代码可以尝试通过基类指针销毁派生类对象,如果基类的析构函数是非虚拟的,则结果未定义。如果析构函数是受保护的,那么调用代码就不能通过基类指针进行销毁,并且析构函数不需要是虚拟的;它确实需要受到保护,而不是私有,以便派生的析构函数可以调用它。通常,基类的编写者不知道销毁时要执行的适当操作。

因此,如果它受到保护,析构函数就不需要是虚拟的。但是,有一个例外:

例外我们可以想象一种情况,您可能需要一个受保护的虚拟析构函数:当一个派生类型的对象(并且只有这种类型)应该被允许通过指向基的指针来销毁另一个对象(而不是它自己)时。不过,我们在实践中还没有看到这样的案例。

因此,总而言之,实际上受保护的析构函数不需要是虚拟的。

于 2018-08-23T11:29:16.133 回答
6

是的,如果您打算在 COM 对象中实现时非常常见delete this的成员函数中执行。class ParentIUnknown::Release()

于 2012-01-23T11:09:32.420 回答
4

protected: Base::~Base();至少如果您(计划)删除BaseBase.Base

于 2012-01-23T11:06:15.977 回答