2

ここでかなり基本的な概念が欠けている場合は申し訳ありませんが、複数のクラス型 (すべて同じ親から派生) のコレクションを維持し、それらを取得するときにサブクラス固有のメソッドにアクセスできるようにする方法を見つけようとしています。コレクションから。

コンテキストとして、1 つの基本クラス (「BaseClass」) と、この基本クラスからすべて派生した多数のクラス (「SubClassA」から「SubClassZ」など) があります。また、作成したすべての SubClass オブジェクトの中央インデックス付きコレクションを維持する必要があります。

typedef unordered_map<std::string, BaseClass*> ItemCollectionType;
ItemCollectionType Items;

リストには SubClass オブジェクトのみが含まれますが、リストのメンバー型を「BaseClass」ポインターとして定義して、任意のサブクラスのインスタンスを格納できるようにしました。これまでのところ、このアプローチには特に悪い点はないと思います (ただし、間違っている場合は訂正してください)。

私が抱えている問題は、これらのコレクションとそのコンテンツのコピーを作成する必要がある場合があることです。このための(簡略化された)コードは次のとおりです。

ItemCollectionType CopiedItems;
ItemCollectionType::const_iterator it_end = Items.end();

for (ItemCollectionType::const_iterator it = Items.begin(); it != it_end; ++it) 
{
    BaseClass *src = it->second;
    BaseClass *item = new BaseClass(src);
    NewItems[item->code] = item;
}

ここでの明らかな問題は、コンパイラが "src" が実際に指している SubClass のコピー コンストラクターではなく、BaseClass のコピー コンストラクターのみを呼び出すことです。

このような状況で推奨されるアプローチは何ですか? タイプ BaseClass のコレクションに追加することによって、このサブクラス タイプ情報を「失う」状況に陥る必要がありますか? コレクションを維持する他の方法は見当たりませんが、より良い代替手段があれば教えてください。

各 SubClass オブジェクトには、サブクラスのフレーバーを示す数値 ID が含まれています。その結果、この数値 ID を「型」オブジェクトに変換する関数を作成し、それを使用してコピー コンストラクターを呼び出す前にソース オブジェクトをキャストすることは可能ですか? これはテンプレート化の有効な用途ですか?

もちろん、これはひどいプログラミング手法であったり、不可能であったりする可能性があります。私は、最も単純で保守性の低いソリューションよりも優れたオプションがあるはずだと確信しています

switch (src->code)
{
    case SubClassTypes::VarietyA:
        SubClassA *item = new SubClassA( *((SubClassA*)src) );
        Items[item->code] = item;
        break;
    case SubClassTypes::VarietyB:
        SubClassB *item = new SubClassB( *((SubClassB*)src) );
        Items[item->code] = item;
        break;
    ...
    ...
}
4

2 に答える 2

3

Clone各サブクラスに実装される抽象メソッドを定義できます。

virtual BaseClass* Clone() = 0;

呼び出すだけではありません:

for (ItemCollectionType::const_iterator it = Items.begin(); it != it_end; ++it) 
{
    BaseClass *src = it->second;
    NewItems[item->code] = src->Clone();
}

また、C++ は戻り値の共分散をサポートしているため、派生クラスは基本クラスだけでなく正確な型を返すことができることに注意してください。

// in DerivedClass (which derives from BaseClass)
DerivedClass* Clone() { ... } 

戻り値の型は基本クラスと同じではありませんが、これは適切なオーバーライドと見なされます。

属性に基づいて、基本クラスのポインターを派生クラスにキャストすることは、適切な OOP プラクティスとは見なされません。

于 2012-09-16T13:59:06.827 に答える
2

サブクラスに新しい関数を作成します(おそらく、基本クラスで純粋仮想にします)。これは、次のようなものです。

BaseClass * SubClassA::copy(){ /* Copy construtor like code. */ }

これにより、BaseClass->copy() を呼び出し、サブクラスでコピー コンストラクターを呼び出すと、動的バインディングが呼び出されます。

于 2012-09-16T13:58:32.460 に答える