2017-08-09 1 views
-1

私は有向非循環グラフのデータ構造を持っています。そこには、複数のタイプの親ノードとリーフがあります。このグラフを出力する関数(BuildGraph)があり、他の関数はそれを処理します(ProcessGraph)。 2つの機能は別々のファイル.cppにありますが、データ構造が定義されている.hファイルは両方に含まれています。データクラスが処理クラスにアクセスできない場合、動的キャストとスイッチを削除するにはどうすればよいですか?

ProcessGraphには多くのswitchステートメントがありますが、グラフ・ノードは処理方法にアクセスできないため、仮想関数で置き換えることはできません。私はそれらの文を削除したいですが、私はどのようにわかりません。 C++でこのような問題を解決するには、どのような方法が好ましいですか?

データ構造:

enum NodeType { 
    GROUP_TYPE_1 = 1, 
    GROUP_TYPE_2 = 2, 

    LEAF_TYPE_1 = 3, 
    LEAF_TYPE_2 = 4, 
    LEAF_TYPE_3 = 5 
}; 

struct Node { 
    const NodeType type; 
    Node(NodeType _type) : type(_type) {} 
    virtual ~Node() {} 
}; 

struct Group { 
    std::vector<std::shared_ptr<Node>> nodes; 
}; 

struct GroupNode1 : public Node, public Group { 
    GroupNode1() : Node(GROUP_TYPE_1) {} 
    /*...*/ 
}; 
struct GroupNode2 : public Node, public Group { 
    GroupNode2() : Node(GROUP_TYPE_2) {} 
    /*...*/ 
}; 

struct LeafNode1 : public Node { 
    LeafNode1() : Node(LEAF_TYPE_1) {} 
    /*...*/ 
}; 
struct LeafNode2 : public Node { 
    LeafNode2() : Node(LEAF_TYPE_2) {} 
    /*...*/ 
}; 
struct LeafNode3 : public Node { 
    LeafNode3() : Node(LEAF_TYPE_3) {} 
    /*...*/ 
}; 

struct Graph { 
    std::shared_ptr<Node> root; 
    /*...*/ 
}; 

BuildGraph:

Graph g; 

// create a diamond shape 
std::shared_ptr<GroupNode2> root = std::make_shared<GroupNode2>(); 
g.root = root; 

std::shared_ptr<GroupNode1> c1 = std::make_shared<GroupNode1>(); 
root->nodes.push_back(c1); 

std::shared_ptr<GroupNode2> c2 = std::make_shared<GroupNode2>(); 
root->nodes.push_back(c2); 

std::shared_ptr<Node> l1 = std::make_shared<LeafNode2>(); 
c1->nodes.push_back(l1); 
c2->nodes.push_back(l1); 

return g; 

ProcessGraph:

void ProcessGraph(std::shared_ptr<Node> root) { 

    switch (root->type) { 
     case NodeType::GROUP_TYPE_1: 
     case NodeType::GROUP_TYPE_2: 
     { 
      Group* g = dynamic_cast<Group*>(root.get()); 
      for (std::shared_ptr<Node>& node : g->nodes) { 
       ProcessGraph(node); 
      } 

      switch (root->type) { 
       /* for each group type */ 
      } 
     } 
      break; 

     case NodeType::LEAF_TYPE_1: 
     { 
      LeafNode1* l = dynamic_cast<LeafNode1*>(root.get()); 
      /* ... */ 
     } 
      break; 
     case NodeType::LEAF_TYPE_2: 
     { 
      LeafNode2* l = dynamic_cast<LeafNode2*>(root.get()); 
      /* ... */ 
     } 
      break; 

     case NodeType::LEAF_TYPE_3: 
     { 
      LeafNode3* l = dynamic_cast<LeafNode3*>(root.get()); 
      /* ... */ 
     } 
     break; 
    } 

} 
+0

switch文を削除するのではなく、それぞれの 'case'を扱うための関数を別々に書くことができます。 – AndyG

答えて

4

あなたはそのためにビジターパターンを使用することができます。 NodeクラスにApply関数を追加し、それを各派生クラスでオーバーライドして、IVisitorインターフェースで一致するvisitメソッドを呼び出します。次に、各操作に対して1つの具体的なビジターを実装します。ノード型が安定していると仮定すると、ノード派生クラスにすべての演算を追加したくない場合は、これは良いアプローチになります。コードが必要な場合は、Webを検索します。

+0

私の評判では、私はその質問のためにどんなdownvoteも見ません。私はそれが知ることができるとは思わないので、仮定しないでください... – Phil1970

関連する問題