多くの場合、オブジェクトのインターフェイスを分離するための抽象基本クラスを用意することをお勧めします。
問題は、C++ではデフォルトでコピー構築であるIMHOがかなり壊れており、コピーコンストラクターがデフォルトで生成されていることです。
では、抽象基本クラスと派生クラスに生のポインタがある場合の落とし穴は何ですか?
class IAbstract
{
~IAbstract() = 0;
}
class Derived : public IAbstract
{
char *theProblem;
...
}
IAbstract *a1 = new Derived();
IAbstract a2 = *a1;//???
そして、階層全体のコピー構築を完全に無効にしますか? IAbstract
でコピー構成をプライベートとして宣言しますか?
抽象基本クラスの3つのルールはありますか?
抽象クラスのコピー構築は、ほとんどの場合、割り当て演算子と同様にプライベートにする必要があります。
抽象クラスは、定義により、ポリモーフィック型になります。そのため、インスタンスが使用しているメモリの量がわからないため、安全にコピーまたは割り当てることができません。実際には、スライスのリスクがあります: https://stackoverflow.com/questions/274626/what-is-the-slicing-problem-in-c
C++では、ポリモーフィック型を値で操作してはなりません。参照またはポインター(または任意のスマートポインター)で操作します。
これが、Javaがオブジェクトを参照によってのみ操作可能にした理由であり、C#とDがクラスと構造体の間の分離を持っている理由です(最初のものはポリモーフィックで参照タイプで、2つ目は非ポリモーフィックおよび値型)。
もちろん、それを保護して空にして、派生クラスが選択できるようにすることもできます。ただし、より一般的には、コードは禁止されていますとにかく純粋な仮想関数があるため、IAbstract
-をインスタンス化することは不可能であるためです。そのため、これは通常は問題ではありません。インターフェイスクラスはインスタンス化できないため、コピーすることはできません。派生クラスは、必要に応じてコピーを禁止または続行できます。
Ctorと割り当てをプライベートにする(またはそれらをC++ 11で= deleteと宣言する)と、コピーが無効になります。
ここでのポイントは、それを行う必要がある場所です。コードを維持するために、IAbstractは問題になりません。 (あなたがしたことをすることに注意してください、あなたは_*a1
_ IAbstract
サブオブジェクトをa2に割り当て、Derived
への参照を失います。値の割り当ては多態的ではありません)
問題は_Derived::theproblem
_で発生します。 Derivedを別のDerivedにコピーすると、実際には、共有するように設計されていない_*theproblem
_データが共有される場合があります(デストラクタで_delete theproblem
_を呼び出す可能性のあるインスタンスが2つあります)。
その場合、Derived
はコピー不可で割り当て不可でなければなりません。もちろん、IAbstract
のコピーを非公開にすると、Derived
のデフォルトのコピーでそれが必要になるため、Derived
もコピーできなくなります。ただし、IAbtract
copyを呼び出さずに独自のDerived::Derived(const Derived&)
を定義した場合でも、それらをコピーできます。
問題はDerivedにあり、ソリューションはDerivedにとどまる必要があります。それがポインターまたは参照によってのみアクセスされる動的のみのオブジェクトでなければならない場合、それ自体がDerivedである必要があります。
_class Derived
{
...
Derived(const Derived&) = delete;
Derived& operator=(const Derived&) = delete;
};
_
基本的に、Derivedクラスの設計者(Derivedの動作方法とtheproblem
の管理方法を知っている必要があります)が、割り当てとコピーの処理方法を決定します。