Blindy の答えは非常に良い (+1) ですが、答えを完成させるだけです。動的継承を使用して、ライブラリを使用せずにそれを行う別の方法があります。
class MyFieldInterface
{
int m_Size; // of course use appropriate access level in the real code...
~MyFieldInterface() = default;
}
template <typename T>
class MyField : public MyFieldInterface {
T m_Value;
}
struct MyClass {
std::map<string, MyFieldInterface* > fields;
}
長所:
- どの C++ コーダーにもなじみがある
- Boost の使用を強制するものではありません (一部のコンテキストでは許可されていません)。
短所:
- オブジェクトをヒープ/フリーストアに割り当て、値セマンティックではなく参照セマンティックを使用してそれらを操作する必要があります。
- そのように公開されたパブリック継承は、動的継承の過剰使用と、実際には相互依存しすぎている型に関連する多くの長期的な問題につながる可能性があります。
- オブジェクトを所有する必要がある場合、破壊を管理する必要があるため、ポインタのベクトルは問題があります。
したがって、可能であれば boost::any または boost::variant をデフォルトとして使用し、それ以外の場合にのみこのオプションを検討してください。
最後の短所を修正するには、スマート ポインターを使用できます。
struct MyClass {
std::map<string, std::unique_ptr<MyFieldInterface> > fields; // or shared_ptr<> if you are sharing ownership
}
ただし、潜在的により問題のある点がまだあります。
new/delete (または make_unique/shared) を使用してオブジェクトを作成する必要があります。これは、実際のオブジェクトが、アロケーター (ほとんどの場合デフォルトの場所) によって提供される任意の場所のフリー ストア (ヒープ) に作成されることを意味します。したがって、オブジェクトのリストを非常に頻繁に参照することは、キャッシュ ミスのために可能な限り高速ではありません。
このリストを可能な限り高速にループするパフォーマンスに関心がある場合(そうでない場合は以下を無視してください)、boost::variant (使用するすべての具象型が既にわかっている場合) またはある種の型消去されたポリモーフィック コンテナーを使用します。
コンテナは同じ型のオブジェクトの配列を管理するが、それでも同じインターフェイスを公開するという考え方です。そのインターフェイスは、概念 (ダックタイピング手法を使用) または動的インターフェイス (最初の例のような基本クラス) のいずれかです。利点は、コンテナが同じタイプのオブジェクトを別々のベクトルに保持するため、それらをすばやく処理できることです。あるタイプから別のタイプに移動するだけではありません。
以下に例を示します (画像はそこからのものです): http://bannalia.blogspot.fr/2014/05/fast-polymorphic-collections.html
ただし、この手法は、オブジェクトが挿入される順序を維持する必要がある場合に役立ちます。
いずれにせよ、いくつかの解決策が考えられますが、それはニーズに大きく依存します。ケースの経験が十分でない場合は、例で最初に説明した単純な解決策か、boost::any/variant のいずれかを使用することをお勧めします。
この回答を補完するものとして、使用できるすべての C++ 型消去手法をコメントと長所/短所とともにまとめた非常に優れたブログ記事を紹介したいと思います。