2010-12-02 10 views
0

共通の親クラスを使用して同じコンテナに異なる型のオブジェクトを格納した後、それらを元に戻す必要があります。ベースクラスコンテナから派生クラスを抽出するには?

[テスト/ test0.C++]

int main() 
{ 
    element wrapper; 
    wrapper.name = "div"; 
    wrapper.attributes["id"] = "wrapper"; 

    cargo<string> text("Learn from yesterday, live for today, hope for tomorrow."); 

    wrapper.children.push_back(&text); 

    cout << "Name:\t" << wrapper.name << endl; 

     /* I have an explicit cast here, 
      * but it can't be used this way 
      * since children may have different types 
      */ 
    cout << "Cargo:\t" << ((cargo<string>*) wrapper.children[0])->value << endl; 

    return 0; 
} 

[ソース/ element.h]

struct element 
{ 
    std::string name; 
    std::map< std::string, std::string > attributes; 
    std::vector< node* > children; 
}; 

[ソース/ node.h]

struct node 
{ }; 

[ソース/ cargo.h]

template <typename Type> 
struct cargo 
    : public node 
{ 
    Type value; 

    cargo(Type value) 
     : value(value) 
    { } 
}; 

私が代わりにそのハードの...本当のノードタイプに関連付けられるタイプのホルダーのいくつかの種類があり、遠く鋳造、抽出操作でそれを使用する必要があります私のテストで1つをコード化しました。

UPDATE:

私は何をしようとしていることは、私のXMLのような言語パーサのためのシンボルテーブルエントリとしてそれを使用する簡単なドキュメントオブジェクトモデルのデータ構造です。私は既存のXMLライブラリを非常に大規模なものとして使用したくありません。私はDOMの考え方は単純だと思います。例えば、DOMツリー内のノードの汎用型をcargo<Type>を使って許可するなど、より複雑な操作に簡単に取り入れることができます。私が採用したデザインが最も適切ではないかもしれないことを認識しています!だから私は提案に開放されています!

助けてくれてありがとう!

+0

は、<> ''貨物に対する操作の多くを実行することを期待していますか? – Nim

+0

おそらく、ノードには仮想Dctorがあるはずです。 – Marcin

+0

@ニム:貨物の唯一の必要性は値を格納することです。余分な操作は追加されません。貨物にテンプレートパラメータとして渡される 'Type'はすべてのビジネスを含みます。 – Rizo

答えて

1


に役立ちます。この質問はおそらく実装よりも設計の詳細です。
Boost.VariantとBoost.Anyは機能しますが、回避策にすぎません。実際の問題は、ノードクラスから派生したクラスの責任の可変部分がカプセル化されていないことです。
代わりに合成を使用できます。 1つのホストクラスが、共通のインタフェースとコンポーネント/代理人/その他の適切な量に使用されます(これらはソリューション設計から生まれるものです)。

またはまったく異なる解決策があなたに合うかもしれません。あなたは、メタプログラミングの言葉に挑戦して、共通のインターフェースを捨てたいかもしれません。代わりにタプル(型リスト)のようなエンティティが役立つかもしれません。

よろしく、
マルチン

+0

はい、そうですよ!これは、実装よりも設計に関するものです...私はこの目的のために使用される関連するデータ構造とテクニック(アルゴリズム、パターン、トリックなど)に関する_real_経験はありません。私は物事を明確かつ包括的に保つために努力していますが、このような実装上の問題につながります。あなたが言及したソリューションを検索します。ありがとう! :) – Rizo

1

単純なストリーミングの場合は、基本クラスでストリーム演算子を実装し、派生クラスのメソッドに委譲します。それ以外の場合は訪問者パターンを見ます。あなたはcargo上でやっている可能性がある操作の種類の本当の把握を持たず、更なる提案をすることは困難です...

1

あなたが検索で多形の容器のメンバーを処理する予定がない場合は、Boost.Variantがあるかもしれません決定的な方法でコンテナメンバーをラップするのに便利です。

バリアントクラステンプレートは、一般的に安全、 であり、スタックベース 均一的にタイプの異種の集合からオブジェクト を操作するための簡単な ソリューションを提供し、 組合コンテナを判別。 std :: vectorなどの標準 コンテナは "マルチ値、シングル タイプ"と考えられる であるのに対し、バリアントは "マルチタイプ、シングル 値"と考えられます。

this prior questionにいくつかのコード例があります。

0

あなたはキャストなしでこのような何かを得ることはありません。

しかし、最も重要なことは、これはしばしば間違った方向に向いていることを意味します。限り、あなたはnodeから公に継承しcargoを決めたとして、次の2つのクラス間の非常に強力な関係を提供し、「nodeであること」よりはるかに強い意味を持っている:私は、コンテナ に挿入することができ

を他node派生タイプ

と一緒に私たちはnodeと何さらにあなたを助けるためにそれを行うことができているかを知る必要があります。しかし、あなたが本当にあなたの初期の解決策に固執する必要がある場合は、boost.variantがあなたを助けることができます。

+0

'node'クラスの唯一の目的は' vector'に格納されたコンテナです。'TextNode'と' ElementNode'のような別々のクラスを作成することができましたが、内容に関して一般的なものを保持したいと思います... – Rizo

0

コードでは、基本クラスの種類を気にしないように設計する必要があります。すべてのユーザーに同じインターフェイスを提供します。または、必要な純粋な仮想メソッドを基本クラスに追加し、派生クラスに実装します。

これは可能ではないと思われる場合は、dynamic_castを試してみましたか?キャストが失敗した場合はnullを返します。

希望これは、 Beezler

+0

私は 'dynamic_cast'を使って考えましたが、要求された目的のために使用しません。 'dynamic_cast'は、その型より先に知っている必要もあります。私が非ヌルキャスティングをチェックするためにそれを使用しない限り...(?) – Rizo

+0

私は最後の手段としてキャスティングを残します。実装することができるビヘイビアまたは抽象メソッドを追加して、キャストする機能を取得します。 – beezler

関連する問題