2017-02-10 3 views
1

먼저 이것이 중복 된 경우 미안합니다. 나는 비슷한 것을 보지 못했다.서브 클래 싱 된 노드를 통해 방문자가있는 C++ 방문자 패턴은 "is a"관계를 잃습니다.

저는 방문자 패턴에 익숙하며 그래프에 방문자를 좀 더 유연하게 추가하려고합니다. 노드 클래스 A, B, C, SubB (B를 상속)가있는 경우 B 노드를 수락하고 (accept() 정의) 그에 대해 모른 채 SubB 노드를 자동으로 수락하는 방문자를 가질 수 있기를 원합니다.

명백한 이점은 하루 종일 하위 클래스로 분류 할 수 있으며 방문자는 해당 유형에 대한 방문 정의에 신경 쓸 필요가 없다는 것입니다.

아래에 설명 할 코드와 결과가 있습니다. 보시다시피 방문 할 노드가 있습니다.

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

는 기본적으로 CountVisitor는 정확하게 2 명 조식을 발견보고하고 그 이유를 이해합니다. 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)의 방법 Visitor 클래스? 그것은 당신이 원하는 행동을 얻는 것처럼 보입니다. –

+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

물론, 좋은 'functor. 고마워. 고마워. – extracrispy