【问题标题】:Is there a use for making a protected destructor virtual?将受保护的析构函数设为虚拟是否有用?
【发布时间】:2012-02-16 17:36:24
【问题描述】:
/*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 的析构函数设为虚拟,那么我会得到一个错误,那么将受保护的析构函数设为虚拟的目的是什么?

【问题讨论】:

  • 也许我们应该从“为什么要保护 dtor?”开始。
  • 你为什么想让析构函数虚拟化? 不应该知道目的吗?受保护的析构函数意味着不应该通过基指针来破坏对象,因此main 中的代码是完全错误的。
  • 我了解虚拟 dtor 和受保护 dtor 的使用,但我看到了一些带有虚拟受保护 dtor 的代码。我不明白的是,当两者都使用时会产生什么效果?
  • @CatPlusPlus:通过使 dtors 受到保护,您将防止在堆栈上创建基类对象。我有仪式吗?

标签: c++ inheritance protected virtual-destructor


【解决方案1】:

举个例子:假设你有一个实现引用计数的基类。你有一个addRef 和一个release 方法,并且你希望你的对象被销毁,如果(并且只有如果)内部计数器通过调用release 达到零。

所以,首先你希望你的析构函数受到保护(因为你只想从release 中销毁对象)。

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

【讨论】:

  • 不,无论派生类是否需要任何额外的破坏,您都需要一个虚拟析构函数,否则行为只是未定义的。
  • @sharptooth 对,我没有想到这一点。已修复,谢谢指出!
  • 我看到一些代码使用这个技巧来强制所有破坏通过友元 C 风格的包装函数(每个派生类定义)。我猜意图是相似的,但在维护下丢失了。
  • @MartinStettner 看我的回答:受保护的析构函数不需要是虚拟的。
【解决方案2】:

an entry in the C++ Core Guidelines 专门针对这个特定主题:

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

原因 防止未定义的行为。如果析构函数是公开的, 然后调用代码可以尝试销毁派生类对象 通过基类指针,如果基类的结果是未定义的 类的析构函数是非虚拟的。如果析构函数受到保护, 那么调用代码不能通过基类指针和 析构函数不需要是虚拟的;它确实需要保护, 不是私有的,因此派生的析构函数可以调用它。一般来说, 基类的编写者不知道要执行的适当操作 销毁时完成。

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

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

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

【讨论】:

  • libhdf5 在 H5Object 中使用虚拟保护析构函数。我不知道这是一个有效的例子还是只是一个错误。
【解决方案3】:

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

【讨论】:

  • 不错。如果depete pBase; attampted,那么任何其他派生类。
【解决方案4】:

protected: Base::~Base(); 至少应该是虚拟的,如果您(计划)删除从BaseBase 的派生类中的Base 派生的任何对象。

【讨论】:

  • @user1085822:所以,你在感谢我的同时不接受我的回答。你想告诉我什么?
  • 这不应该只是
  • 这不应该只是 - “protected: Base::~Base(); 如果您(计划)删除从 Base 中的 Base 派生的任何对象,至少应该是虚拟的”?为什么是“或 Base 的派生类”。部分?
猜你喜欢
  • 2020-03-06
  • 2016-01-22
  • 2012-11-23
  • 2023-03-23
  • 2013-11-03
  • 2012-11-06
  • 2012-12-24
  • 2011-03-15
  • 2011-06-01
相关资源
最近更新 更多