27

私は周りを検索しましたが、これを実行するには、Baseクラスを変更する必要があり、これが最善のアプローチであるかどうかを知りたいようです。たとえば、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メソッドを実装する必要があります。

それで、これを行うためのはるかに簡単で標準的な方法はありますか?

4

3 に答える 3

32

仮想コピーパターンを使用する必要があります。インターフェイスで仮想関数を提供してコピーを実行し、それを階層全体に実装します。

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() )
   {}
};
于 2012-09-04T01:00:18.557 に答える
24

関数を使用するアプローチを使用するclone()ことは、優れたソリューションです。CRTP (奇妙に繰り返されるテンプレート パターン)を使用すると、作業の一部を節約できることに注意してください。BaseCRTPその方法は、テンプレートであり、clone()関数を実装する中間レベル (以下で呼び出されます) を導入することです。実際のクラスを派生させるときは、それらを派生元のベースのテンプレート引数として使用します。彼らは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())
  {}
};
于 2012-09-04T01:11:58.327 に答える
1

この状況では、テンプレートが最適な方法だと思います。

template<typename Sub>
class DeepCopy
{
    Base *base;

    DeepCopy(Sub *sub)
    {
        base = new Sub(*sub); // use copy constructor
    }
}

これはDeepCopy、 が互いに割り当てられないことを意味しますが、それは C++ で支払う代償です。

于 2012-09-04T01:00:45.367 に答える