私有地继承具有非虚拟析构函数的类是否安全?

Cla*_*dio 15 c++ inheritance destructor

据我所知,与公有继承时,通常不是安全时,由于delete荷兰国际集团一个基类指针编译器只生成的代码来调用基类的析构函数,并且派生类的一个不叫.

但是对于私有继承,客户端不能将派生类指针强制转换为基类指针(因为私有继承不建模is-a关系),所以delete总是在派生类的指针上使用,编译器应该能够看到那里也是一个基类并调用它的析构函数.

我做了这个测试:

#include <iostream>

struct BaseVirtual
{
    virtual ~BaseVirtual()
    {
        std::cout << "BaseVirtual's dtor" << '\n';
    }
};

struct BaseNonVirtual
{
    ~BaseNonVirtual()
    {
        std::cout << "BaseNonVirtual's dtor" << '\n';
    }
};

struct DerivedPrivVirtual: private BaseVirtual
{
    static void f()
    {
        BaseVirtual * p = new DerivedPrivVirtual;
        delete p;
    }

    ~DerivedPrivVirtual()
    {
        std::cout << "DerivedPrivVirtual's dtor" << '\n';
    }
};

struct DerivedPrivNonVirtual: private BaseNonVirtual
{
    static void f()
    {
        BaseNonVirtual * p = new DerivedPrivNonVirtual;
        delete p;
    }

    ~DerivedPrivNonVirtual()
    {
        std::cout << "DerivedPrivNonVirtual's dtor" << '\n';
    }
};

int main()
{
    std::cout << "With explicit derived pointer type:" << '\n';
    {
        DerivedPrivVirtual * derivedPrivVirtual = new DerivedPrivVirtual;
        DerivedPrivNonVirtual * derivedPrivNonVirtual = new DerivedPrivNonVirtual;

        delete derivedPrivVirtual;
        delete derivedPrivNonVirtual;
    }
    std::cout << '\n';

    std::cout << "With base pointer type:" << '\n';
    {
        // Client code can't cast Derived to Base when inherit privately.
        //BaseVirtual * derivedPrivVirtual = new DerivedPrivVirtual;
        //BaseNonVirtual * derivedPrivNonVirtual = new DerivedPrivNonVirtual;

        //delete derivedPrivVirtual;
        //delete derivedPrivNonVirtual;
    }
    std::cout << '\n';

    std::cout << "Inside derived class itself:" << '\n';
    {
        DerivedPrivVirtual::f();
        DerivedPrivNonVirtual::f();
    }
    std::cout << '\n';

    std::cout << "With non-dynamic variables:" << '\n';
    {
        DerivedPrivVirtual derivedPrivVirtual;
        DerivedPrivNonVirtual derivedPrivNonVirtual;
    }
    std::cout << '\n';
}
Run Code Online (Sandbox Code Playgroud)

GCC 4.7.1和CLang 3.1都提供相同的输出.调用派生类构造函数,除非派生类本身将派生类指针强制转换为基类和delete它.

除了这个看起来非常罕见且容易避免的案例(班级的作者是唯一可以造成伤害的人,但它确实从哪个类中得知它的来源),我能否得出结论它是安全的?

With explicit derived pointer type:
DerivedPrivVirtual's dtor
BaseVirtual's dtor
DerivedPrivNonVirtual's dtor
BaseNonVirtual's dtor

With base pointer type:

Inside derived class itself:
DerivedPrivVirtual's dtor
BaseVirtual's dtor
BaseNonVirtual's dtor  <-- Only a problem inside the class itself

With non-dynamic variables:
DerivedPrivNonVirtual's dtor
BaseNonVirtual's dtor
DerivedPrivVirtual's dtor
BaseVirtual's dtor
Run Code Online (Sandbox Code Playgroud)

奖金问题:保护继承怎么样?我认为做损害的能力不再是直接派生类作者的特权,而是层次结构中任何类的作者.

Dav*_*eas 10

无论继承是公共还是私有都不会影响代码的安全性,它只是限制了安全/不安全使用的范围.您有相同的基本问题:如果您的类或您的类的朋友将您的类型的对象传递给一个接口,该接口在没有虚拟析构函数的情况下获取指向基础的指针,并且该接口获得对象的所有权,那么您创建的是未定义的行为.

设计中的问题是,根据您的问题,BaseNonVirtual设计不是为了扩展.如果是,它应该具有公共虚拟析构函数或受保护的非虚拟析构函数,确保没有代码能够通过指向基础的指针调用派生对象上的删除.