我知道使用公共继承通常是不安全的,因为当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';
}
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
额外的问题:受保护的继承呢?我认为造成伤害的能力不再是直接派生类的作者的特权,而是层次结构中任何类的作者的特权。