虚拟析构函数必须是公共的吗

Do virtual destructors have to be public?

本文关键字:析构函数 虚拟      更新时间:2023-10-16

我发现几乎每个虚拟析构函数的代码片段都将其作为公共成员函数,如下所示:

class Base
{
public:
    virtual ~Base()
    {
        cout << "~Base()" << endl;
    }
};
class Derived : public Base
{
public:
    ~Derived()
    {
        cout << "~Derived()" << endl;
    }
};

虚拟析构函数必须是公共的吗?或者在某些情况下,非公共的虚拟析构因子是有意义的吗?

虚拟析构函数必须是公共的吗?或者在某些情况下,非公共的虚拟析构因子是有意义的吗

赛马场。如果需要多态删除,则使用public虚拟析构函数。如果不需要,则析构函数根本不需要是虚拟的。

遵循Herb的建议

准则#4: 基类析构函数应该是公共的和虚拟的,或者是受保护的和非虚拟的。

简而言之,你只剩下两种情况中的一种。任一:

  1. 您希望通过基指针允许多态删除,在这种情况下,析构函数必须是虚拟的和公共的;或
  2. 你没有,在这种情况下,析构函数应该是非虚拟的并受到保护,后者是为了防止不必要的使用

就像非虚拟析构函数一样,不,它们不需要public,但大多数时候它们是。

如果您的类是规则的例外,并且出于任何原因需要控制其实例的生存期,那么析构函数必须是非public。这将影响客户端如何(或不能(使用类的实例,但这当然是重点。由于析构函数是virtual,所以唯一的其他选项是virtual protected

相关:是否有使受保护的析构函数成为虚拟的用途?

如果计划通过特殊方法创建/销毁对象(例如,创建/销毁(,则没有必要。但是,如果您在堆栈或堆上创建对象,则必须具有公共析构函数。

这里的问题是关于虚拟析构函数的,因此我认为为什么需要这样的实现的原因的排列也应该包括继承情况。这个问题的答案取决于以下内容:

1( 如果您不希望类被实例化,您可以使用私有构造函数/析构函数。不过,实例化可以通过同一类中的另一个方法来完成。因此,当你想在类中使用MyDestructor((这样的特定方法来调用析构函数时,析构函数仍然可以放在private下。例如:Singleton设计模式。此外,在这种情况下,它防止类被继承

2( 如果该类是要继承的,则不允许使用私有基类析构函数(引发编译错误(。但是,受保护的基类析构函数允许继承

3( 受保护的虚拟析构函数的继承类型(公共和受保护(允许一种安全的多级继承方式a->B->C,这样当调用C的析构函数时,内存会得到更好的清理。

4( 当使用new动态分配内存时,单独的专用析构函数不能允许删除(我不确定auto_ptr,但我认为即使这样也应该遵循使用"专用"析构函数的相同想法(。

总之,我认为使用私有析构函数可能很容易出错,尤其是当不知道此类实现的人即将使用此类时。

受保护的和公共的析构函数总是受欢迎的,其使用取决于上面给出的需求。

希望这能澄清。

这里涉及两个独立的规则。首先,如果您的设计要求通过指向基的指针删除派生类型的对象,则基中的析构函数必须是虚拟的。其次,如果一个成员函数(我广泛地包括析构函数(是受保护的或私有的,那么可以调用它的上下文比它是公共的时更受限制(当然,如果析构函数是私有的,则不能从类派生(。例如:

class C {
protected:
    virtual ~C();
    friend void destroy_me(C*);
};
void destroy_me(C *cp) {
    delete cp; // OK: destructor is accessible
}
void destroy_someone_else(C *cp) {
    delete cp; // Error: destructor is not accessible
}