私は周りを検索しましたが、これを実行するには、Baseクラスを変更する必要があり、これが最善のアプローチであるかどうかを知りたいようです。たとえば、私は基本クラスを持っています:
class Base {}
次に、派生クラスの長い行:
class Derived_1:: public Base {}
class Derived_2:: public Derived_1{}
...
...
class Derived_n:: public Derived_M{}
そして、私は別のクラスを持っています:
class DeepCopy
{
Base * basePtr;
public:
DeepCopy(DeepCopy & dc) {}
}
BaseクラスとDerived_xクラスのコピーコンストラクターが適切にコーディングされていると仮定すると、DeepCopyのコピーコンストラクターを作成するための最良の方法は何ですか。コピーしようとしているオブジェクトのbasePtrにあるクラスをどのように知ることができますか?
私が考えることができる唯一の方法はRTTIを使用することですが、dynamic_castsの長いリストを使用することは正しくないようです。さらに、DeepCopyはBaseクラスの継承階層について知る必要があります。
私が見た他の方法は ここ です。ただし、BaseクラスとDerivedクラスがcloneメソッドを実装する必要があります。
それで、これを行うためのはるかに簡単で標準的な方法はありますか?
仮想コピーパターンを使用する必要があります。コピーを実行するインターフェイスに仮想関数を提供し、階層全体に実装します。
struct base {
virtual ~base() {} // Remember to provide a virtual destructor
virtual base* clone() const = 0;
};
struct derived : base {
virtual derived* clone() const {
return new derived(*this);
}
};
次に、DeepCopy
オブジェクトはその関数を呼び出す必要があります。
class DeepCopy
{
Base * basePtr;
public:
DeepCopy(DeepCopy const & dc) // This should be `const`
: basePtr( dc.basePtr->clone() )
{}
};
clone()
関数を使用するアプローチを使用することは良い解決策です。 CRTP(不思議なことに繰り返されるテンプレートパターン) を使用すると、作業の一部を節約できます。これを行う方法は、テンプレートであり、clone()
関数を実装する中間レベル(以下ではBaseCRTP
と呼ばれます)を導入することです。実際のクラスを派生させるときは、それらを派生元のベースのテンプレート引数として使用します。 clone()
関数が自動的に実装されます。派生クラスがコピーコンストラクターを実装していることを確認してください(またはデフォルトが必要なものであることを確認してください)。
/* Base class includes pure virtual clone function */
class Base {
public:
virtual ~Base() {}
virtual Base *clone() const = 0;
};
/* Intermediate class that implements CRTP. Use this
* as a base class for any derived class that you want
* to have a clone function.
*/
template <typename Derived>
class BaseCRTP : public Base {
public:
virtual Base *clone() const {
return new Derived(static_cast<Derived const&>(*this));
}
};
/* Derive further classes. Each of them must
* implement a correct copy constructor, because
* that is used by the clone() function automatically.
*/
class Derived1 : public BaseCRTP<Derived1> {
/*... should have an ordinary copy constructor... */
};
class Derived2 : public BaseCRTP<Derived2> {
/*... should have an ordinary copy constructor... */
};
その後、通常の方法でDeepCopy
クラスを実装できます。
class DeepCopy
{
Base *basePtr;
public:
DeepCopy(const DeepCopy &dc)
: basePtr(dc.basePtr->clone())
{}
};
この状況では、テンプレートが最善の方法だと思います。
template<typename Sub>
class DeepCopy
{
Base *base;
DeepCopy(Sub *sub)
{
base = new Sub(*sub); // use copy constructor
}
}
これは、DeepCopy
が相互に割り当てられないことを意味しますが、それはC++で支払う価格です。