すべて、これは単純な問題のように思えますが、私にはぴったりです。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() メソッドの各派生クラスを順番に呼び出します。これはすべて正常に機能しますが、よりエレガントなソリューションが欠けていると考え続けています。私の質問は、あるタイプのオブジェクトを持つコンテナがある場合、そのコンテナを含むクラスをどのようにコピーすればよいのでしょうか? それが理にかなっていることを願っています。
1 に答える
あなたがしたことは、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 のコンストラクターのコードは、派生クラスのコンストラクターが呼び出されて、仮想メソッド テーブル ポインターを派生クラスのポインターにスワップ アウトする前に実行されます。したがって、コンストラクターで仮想メソッド呼び出しを行った場合、それらはクラスから派生したクラスには移動しません。それでおしまい。