2017-02-10 10 views
1

まず、重複している場合はごめんなさい。私は同じようなものは見ませんでした。サブクラス化されたノード上の訪問者がいるC++訪問者パターンは "is a"の関係を失う

私はビジターパターンに精通しており、私は自分のグラフ上でビジターに少しの柔軟性を加えようとしています。ノードクラスA、B、C、SubB(Bを継承する)がある場合、Bノードを受け入れ、それらを知らずにSubBノードを自動的に受け入れる訪問者を持つことができるようにしたいと思います。

明白な利点は、私が終日サブクラス化することができ、ビジターはそれらのタイプの訪問の定義を気にする必要がないことです。

以下に示すコードと結果があります。 ご覧のとおり、訪問するノードがあります。

new Node(), 
new ANode(), 
new BNode(), 
new CNode(), 
new BNode(), 
new SubBNode() 

基本的にCountVisitorは正しく、それは2つのBsを見つけ報告し、私は理由を理解。 CountVisitor.visit(SubB &)はオーバーライドされず、Visitor.visit(SubB &)にリダイレクトされるため、カウントはスキップされます。しかし、私はSubBが "B"なので、3(2 Bs + 1 SubB)を報告する機能を望んでいます。これについて考えてきたので、型システムにする方法を理解できません。その機能を実現するために、どのように物事を並べ替えるべきですか?私はまた、 "それは"関係を維持する場合、代替パターンにも開いていますが、この障害が解決されれば訪問者は完璧だと思います。

#include <iostream> 
#include <string> 
#include <vector> 

using namespace std; 

class Visitor; 

class Node 
{ 
    public: 
    vector<Node*> children; 
    virtual void accept(Visitor&); 
}; 

class ANode : public Node 
{ 
    public: 
    virtual void accept(Visitor&); 

}; 
class BNode : public Node 
{ 
    public: 
    virtual void accept(Visitor&); 
}; 
class CNode : public Node 
{ 
    public: 
    virtual void accept(Visitor&); 
}; 

//-- try inheritance 

class SubBNode: public BNode 
{ 
    public: 
    virtual void accept(Visitor&); 
}; 

//-- 

class Visitor 
{ 
    public: 
    virtual void visit(Node& n); 
    virtual void visit(ANode& n); 
    virtual void visit(BNode& n); 
    virtual void visit(CNode& n); 
    virtual void visit(SubBNode& n); 
}; 

class CountVisitor : public Visitor 
{ 
    public: 
    virtual void visit(BNode& n); 

    int count = 0; 
    void print(); 
}; 
//--------------------------------------------- 

void Node::accept(Visitor& v){ 
    cout << __PRETTY_FUNCTION__ << endl; 
    v.visit(*this); 
} 
void ANode::accept(Visitor& v){ 
    cout << __PRETTY_FUNCTION__ << endl; 
    v.visit(*this); 
} 
void BNode::accept(Visitor& v){ 
    cout << __PRETTY_FUNCTION__ << endl; 
    v.visit(*this); 
} 
void CNode::accept(Visitor& v){ 
    cout << __PRETTY_FUNCTION__ << endl; 
    v.visit(*this); 
} 
void SubBNode::accept(Visitor& v){ 
    cout << __PRETTY_FUNCTION__ << endl; 
    v.visit(*this); 
} 
// ----- 
void Visitor::visit(Node& n){ 
    cout << __PRETTY_FUNCTION__ << "\t\tDEFAULT" << endl; 
} 
void Visitor::visit(ANode& n){ 
    cout << __PRETTY_FUNCTION__ << "\t\tDEFAULT" << endl; 
} 
void Visitor::visit(BNode& n){ 
    cout << __PRETTY_FUNCTION__ << "\t\tDEFAULT" << endl; 
} 
void Visitor::visit(CNode& n){ 
    cout << __PRETTY_FUNCTION__ << "\t\tDEFAULT" << endl; 
} 
void Visitor::visit(SubBNode& n){ 
    cout << __PRETTY_FUNCTION__ << "\t\tDEFAULT" << endl; 
} 
// ----- 
void CountVisitor::visit(BNode& n){ 
    count++; 
    cout << __PRETTY_FUNCTION__ << "\t\tSPECIAL" << endl; 
} 
void CountVisitor::print(){ 
    cout << "CountVisitor Found Bs: "<< count << endl; 
} 


// ==================================================== 

int main() { 

    cout << "======FLAT TEST======" << endl; 
    vector<Node*> nodes = { 
    new Node(), 
    new ANode(), 
    new BNode(), 
    new CNode(), 
    new BNode(), 
    new SubBNode() 
    }; 

    cout << "--DEFAULT--" << endl; 
    Visitor v1; 
    for(Node* n : nodes){ 
    n->accept(v1); 
    } 

    cout << "--COUNT--" << endl; 
    CountVisitor cv1; 
    for(Node* n : nodes){ 
    n->accept(cv1); 
    } 
    cv1.print(); 
    return 0; 
} 

結果

======FLAT TEST====== 
--DEFAULT-- 
virtual void Node::accept(Visitor&) 
virtual void Visitor::visit(Node&)  DEFAULT 
virtual void ANode::accept(Visitor&) 
virtual void Visitor::visit(ANode&)  DEFAULT 
virtual void BNode::accept(Visitor&) 
virtual void Visitor::visit(BNode&)  DEFAULT 
virtual void CNode::accept(Visitor&) 
virtual void Visitor::visit(CNode&)  DEFAULT 
virtual void BNode::accept(Visitor&) 
virtual void Visitor::visit(BNode&)  DEFAULT 
virtual void SubBNode::accept(Visitor&) 
virtual void Visitor::visit(SubBNode&)  DEFAULT 
--COUNT-- 
virtual void Node::accept(Visitor&) 
virtual void Visitor::visit(Node&)  DEFAULT 
virtual void ANode::accept(Visitor&) 
virtual void Visitor::visit(ANode&)  DEFAULT 
virtual void BNode::accept(Visitor&) 
virtual void CountVisitor::visit(BNode&)  SPECIAL 
virtual void CNode::accept(Visitor&) 
virtual void Visitor::visit(CNode&)  DEFAULT 
virtual void BNode::accept(Visitor&) 
virtual void CountVisitor::visit(BNode&)  SPECIAL 
virtual void SubBNode::accept(Visitor&) 
virtual void Visitor::visit(SubBNode&)  DEFAULT 
CountVisitor Found Bs: 2 
+0

はあなたがちょうどで訪問(SubBNode&N)メソッドを取り除くことができますビジタークラス?それはあなたが望む振る舞いを得るように思われます。 –

+0

SubBタイプのものだけを行うように設計された別の訪問者がいる場合を除き、それらのノードにまったく応答することはできません。 – extracrispy

答えて

1

あなたは追加の層を追加することができ、のようなもの:

template <typename F> 
class FunctorVisitor : public Visitor 
{ 
public: 
    explicit FunctorVisitor (F& f) : f(f) {} 

    virtual void visit(Node& n) override { f(n);} 
    virtual void visit(ANode& n) override { f(n);} 
    virtual void visit(BNode& n) override { f(n);} 
    virtual void visit(CNode& n) override { f(n);} 
    virtual void visit(SubBNode& n) override { f(n);} 
private: 
    F& f; 
}; 


class CountVisitor 
{ 
public: 
    void operator() (const Node& n) const { 
     cout << __PRETTY_FUNCTION__ << "\t\tDefault" << endl; 
    } 
    void operator() (const BNode& n) { 
     count++; 
     cout << __PRETTY_FUNCTION__ << "\t\tSPECIAL" << endl; 
    } 

    int count = 0; 
    void print() const { 
     cout << "CountVisitor Found Bs: "<< count << endl; 
    } 
}; 

Demo

+1

もちろん、いいオールドのファンクタ。私はこれが好きです、ありがとう。 – extracrispy

関連する問題