基本クラスのポインターを ing するとき、コンパイラーは基本クラスのデストラクタを呼び出すコードのみを生成し、派生クラスのデストラクタは呼び出されないため、パブリック継承では一般に安全ではないことを理解しています。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
それを s する場合を除き、呼び出されます。
非常にまれで簡単に回避できるこのケース (クラスの作成者は害を及ぼすことができる唯一の人ですが、どのクラスから派生したかを知っています) のほかに、安全であると結論付けることができますか?
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
おまけの質問: 保護された継承についてはどうですか? 危害を加える能力は、直接派生したクラスの作成者にもはや特権ではなく、階層内の任意のクラスの作成者に特権があると思います。