5

バックグラウンド:

私が解決する必要がある同様の状況については、C++ FAQ のこの質問を参照してください。

私は基本クラスを持っていclass Bます。

関数、メンバー、および追加のメモリ割り当てを介して追加機能を追加するclass DB からの派生クラスがあります。

class B追加機能は、何もしないかデフォルト値を返すことによって、および にnullptrs固有の仮想関数からポリモーフィックにサポートされますclass D

class Bpublic static Factory Methodsすべての建設に使用しますprotected constructors。(参照:名前付きコンストラクタイディオム)

class Dクラス B とは異なる名前が付けられ、クラス B では使用できないpublic static Factory Methodsすべての構成に使用します。protected constructors

しばらくして、新しいインターフェイス クラスが作成されclass Aます。このクラスには、派生クラスがclass Aゲッター関数とセッター関数の両方を必要とするようなインターフェースがありますpointer to a class Bが、動的な値はまたはのいずれclass Bかになります。class D

質問:

class Aのコピー コンストラクター、代入演算子、および/またはセッターを派生させて作成したいのですが、はそのメンバーを型のオブジェクトとしてのみ公開するclass Bため、返されたオブジェクトがまたはであるかどうかを判断する方法がありません。class ABclass Bclass D

スライスやメモリの問題を引き起こすことなく、パブリックインターフェイスのみを使用して上記を正しく実装するにはどうすればよいですか (上記の設定が間違っていて変更する必要がある場合を含む)。

可能な解決策?:

いくつかのオプションを試してみたくなりました:

1) クラス B にメンバーを作成し、オブジェクトの型を宣言するすべての派生型を作成します。

if(getB()->GetType() == "D") {
    //Call D::CreateD(...)
} else if(getB()->GetType() == "B") {
    //Call B::CreateB(...)
}

2) 派生型に動的にキャストし、失敗をチェックします。

if(dynamic_cast<D*>(getB()) == nullptr) {
    //Call B::CreateB(...)
} else {
    //Call D::CreateD(...)
}

3)オブジェクトで使用するとclass D返されることがわかっている固有の仮想メソッドを使用します。nullptrclass B

if(getB()->VirtualMethodSpecificToClassD() == nullptr) {
    //Call B::CreateB(...)
} else {
    //Call D::CreateD(...)
}

3 つのケースすべてにコードの匂いがあります。

  1. 「else-if-heimers」を引き起こします。
  2. これが実際に機能するかどうかはわかりません。
  3. 「実装ではなくインターフェースへのコード」のグッドプラクティスに違反しています。
4

1 に答える 1

3

zneakのコメントによると、ファクトリ メソッドとプライベート コンストラクターを使用している場合、

 virtual B* copy() const { return new B(*this); /* calls private B::B(const B&) */ }

クラス内のメソッド、クラスB内でオーバーライドされますD(新しいD*を返します -- この共変の戻り値の型の使用は、C++ で特に許可されています)。

次に、Aコピーコンストラクターは次のようなことができます

A::A(const A& other) : b(other.getB()->copy()) {}

そしてそれはうまくいくはずです。


一方、提案した解決策のいずれかを使用したい場合は、最初の解決策が最も刺激的ではないと思いますが、文字列ではなく列挙型を使用するので、文字列比較ではなく単純な switch ステートメント。C++ RTTI オーバーヘッドを回避するために、LLVM は「動的キャスト」にこのようなものを使用していると思います。

于 2013-11-05T08:06:11.247 に答える