1

すべて、これは単純な問題のように思えますが、私にはぴったりです。Animal と呼ばれる C++ 基本クラスと派生クラス Cat、Dog、Horse、Hippo、Snake があるとします。Animal オブジェクトのリスト (この場合、基本クラス Animal が QObject である Qt List) を含む Zoo という別のクラスがあります。ここでやりたいことは、Zoo オブジェクトを作成し、それを別の Zoo オブジェクトにコピーして、コピー先の Zoo に独自の動物のコピーを持たせることです。問題は Zoo コピー コンストラクターにあります。これは、コンパイラーが行うべきである Dog、Cat などではなく、Animal のコピー コンストラクターを呼び出す動物のリストがあると考えているためです。これを回避するために、アニマル リストをアニマル ポインターのリストに変更し、独自のアニマル コピー コンストラクターと代入演算子を作成しました。これらはそれぞれ Animal::Clone( Animal & rhs ) メソッドは、データのコピーと共にヒープから割り当てられた新しいポインターを返す Animals Clone() メソッドの各派生クラスを順番に呼び出します。これはすべて正常に機能しますが、よりエレガントなソリューションが欠けていると考え続けています。私の質問は、あるタイプのオブジェクトを持つコンテナがある場合、そのコンテナを含むクラスをどのようにコピーすればよいのでしょうか? それが理にかなっていることを願っています。

4

1 に答える 1

2

あなたがしたことは、C ++でそれを行う慣用的な方法です。仮想clone()メソッドは、実際には仮想コピー コンストラクターイディオムとして知られています。通常、次のシグネチャの仮想抽象メソッドとして宣言します。

Animal * clone() const = 0;

パラメータを取らないことに注意してくださいrhs。それ自体のクローンを返すだけです。animal のインスタンスが与えられた場合、次のAnimal * myPetように言うと重複したものを取得できます

Animal * mySecondPet = myPet->clone();

インスタンス化する場合は、派生クラスに実装する必要があります。

[Ed:]お気づきのように、C++ の設計に固有のスライシングの問題により、コンテナー クラスがアイテムをポインターではなく直接保持することは不可能です。

C++ では、あなたのソリューションはイディオムです。それは洗練されたものであり、それを見た人、C++ を知っている人なら誰でも、あなたの言いたいことがすぐにわかるはずです。イディオムと特定の設計パターンは、言語の一部です。人間であろうとプログラミングであろうと、慣用句を知らなければ、言語に堪能であるとは言えません。

Cloneable多くのプロジェクトで、このクローン メソッドだけで構成されるというインターフェイス クラス (すべて抽象仮想メソッド) を使用しています。次に、一部の基本クラスを強制的にクローン可能にするのは簡単です。Cloneable から継承するだけです。たとえば、そのようにQEventなればいいのにと思います。Cloneableこのままでは、複製QEventsして複数のイベント キューに投稿することはできません。

ダニエルの提案「Animal のコピー コンストラクタを仮想化してみましたか?」文字通り受け取ることはできません。実際には、C++ には仮想コピー コンストラクターや任意のコンストラクターなどはありません。単純な理由で、オブジェクトが構築される前に、その仮想メソッド テーブルがファイナライズされていません。具体的には、Animal のコンストラクターのコードは、派生クラスのコンストラクターが呼び出されて、仮想メソッド テーブル ポインターを派生クラスのポインターにスワップ アウトする前に実行されます。したがって、コンストラクターで仮想メソッド呼び出しを行った場合、それらはクラスから派生したクラスには移動しません。それでおしまい。

于 2012-06-27T21:30:49.943 に答える