5

次のクラス階層があるとします。

class Base {
    ...
};

class Derived1 : public Base {
    ...
};

class Derived2 : public Base {
    ...
};

またはオブジェクトのBase*いずれかを指す可能性がある場合、具体的なタイプが不明な場合、実際のオブジェクトのコピーを作成するにはどうすればよいですか。コピー コンストラクターを定義することを考えましたが、関連する実際の型を知らなければ、これは不可能だと思います。私が考えることができる唯一の解決策は、階層内の各型でメソッドを定義することです。もっとエレガントなものを考えられる人はいますか?Derived1Derived2clone()

4

7 に答える 7

13

残念ながら、仮想クローン/コピー パターンが唯一の現実的な選択肢です。

これにはバリエーションがありますが、基本的にはすべて、新しいコピーを返すことができる各型の関数を記述することになります。

于 2009-01-27T01:55:11.293 に答える
4

階層内のすべてのオブジェクトに仮想クローン メソッドを実装する必要があります。未定義の型のオブジェクトが自分自身をコピーする方法を他にどのように知るでしょうか?

派生クラスを書いている人々にこれをより明白にするために、基本クラスでも clone メソッドを抽象化して、人々に少なくとも何かを書くように強制することを考えるかもしれません。

コードのいくつかの場所で、オブジェクトを文字列にシリアル化する to_string() メソッドが正しく実装されていることを確認するテストも行います。clone と to_string を同時にテストするためにクラスで使用した特定のテストは、次のようになります。

Base *obj1, *obj2;
# initialize obj1 in a reasonable manner
obj2 = obj1->clone();
assert( obj1->to_string() == obj2->to_string() );

これは clone method() と文字列へのオブジェクトのシリアル化の両方をテストしています (厳密には単体テストではありません)。 clone() と to_string() を実装するための最低限の基準に従います。

編集:ストレンジャーのコメントからの修正でコードを更新しました。ありがとう!

于 2009-01-27T02:08:02.717 に答える
2

簡単にできるとは思えません。実際、Effective C++ で、Meyers は、値渡しの関数がある場合、次のように警告しました。

void foo(Base b)

Derived1 d1に aを渡すとfoo、コピーが切り捨てられます。つまり、派生部分はコピーされません。

とはいえ、今の記憶からの引用ですが…

于 2009-01-27T01:51:14.717 に答える
0

あなたは正しいですclone()。コンストラクターは静的バインディングを強制するため、使用できません。オブジェクトを値で返すことはできません。これも静的バインディングを強制するためです。したがって、動的に割り当てられたオブジェクトを返す仮想関数が必要です。

于 2009-01-27T02:35:38.480 に答える
0

コンストラクターが呼び出される前にメモリが割り当てられるため、コピーコンストラクターは(私の知る限り)不可能です。オブジェクトの型ではなく、既知の型のコピー コンストラクターが使用されます。

Base *foo = new Derived1();
Base bar = *foo;               // Base's copy constructor is called.

あなたが提案したように、あなたの最善の策はclone()方法を提供することです。

于 2009-01-27T02:09:15.883 に答える
0

Base別の方法は、すべての派生クラスを知っていると仮定して、ファクトリのような を作成することです。

よく考えてみると、これはおそらく悪い考えです。

class Base {
    public:
        static Base *clone(const Base *obj) {
            if((Derived1 *o = dynamic_cast<Derived1 *>(obj)) {
                return new Derived1(*o);
            } else if((Derived2 *o = dynamic_cast<Derived2 *>(obj)) {
                return new Derived2(*o);
            }

            /* TODO When more classes are added, put them here.  (Probably bad design, yes.) */

            return new Base(obj);
        }

        Base *clone() const {
            return clone(this);
        }
};
于 2009-01-27T02:15:43.700 に答える
0

透過的な複製方法が必要な場合は、Implicit Sharingを調べてください。

于 2009-01-27T02:16:48.613 に答える