【发布时间】:2012-09-09 23:40:36
【问题描述】:
我知道使用公共继承通常不安全,因为当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 提供相同的输出。除非派生类本身将派生类指针强制转换为基类并且deletes 它,否则将调用派生类构造函数。
除了这种看起来很不常见且很容易避免的情况(类的作者是唯一可以造成伤害的人,但它确实知道它是从哪个类派生出来的),我可以断定它是安全的吗?
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
额外问题:受保护的继承呢?我想伤害的能力不再是直接派生类的作者的特权,而是层次结构中任何类的作者的特权。
【问题讨论】:
-
如果我没记错的话,Scott Meyers(Effective C++,More Effective C++ 的作者)仍然不知道受保护的继承是什么意思。 Public 是“is-a”关系,Private 是“implemented-in-terms-of”,但受保护?这有点吓人。
标签: c++ inheritance destructor