2011-10-24 57 views
2

我嘗試用模板派生類使用訪問者模式與模板派生類

我與海灣合作委員會的工作4.5

這裏是VisitorTemplate.hpp,我專門在派生類實現Visitor模式參觀者,但我希望能夠處理任何類型:

編輯:感謝interjay的建議,代碼編譯和運行沒有錯誤,現在

#ifndef VISITORTEMPLATE_HPP_ 
#define VISITORTEMPLATE_HPP_ 

#include <iostream> 
#include <string> 
using namespace std; 

template<class T> Derived; 

class Visitor 
{ 
    public: 
    virtual void visit(Derived<string> *e) = 0; 
}; 

class Base 
{ 
    public: 
    virtual void accept(class Visitor *v) = 0; 
}; 

template<class T> 
Derived: public Base 
{ 
    public: 
    virtual void accept(Visitor *v) 
    { 
     v->visit(this); 
    } 
    string display(T arg) 
    { 
     string s = "This is : " + to_string(arg); 
     return s; 
    } 
}; 

class UpVisitor: public Visitor 
{ 
    virtual void visit(Derived<string> *e) 
    { 
    cout << "do Up on " + e->display("test") << '\n'; 
    } 
}; 

class DownVisitor: public Visitor 
{ 
    virtual void visit(Derived<string> *e) 
    { 
    cout << "do Down on " + e->display("test") << '\n'; 
    } 
}; 

#endif /* VISITORTEMPLATE_HPP_ */ 

的main.cpp

Base* base = new Derived<string>(); 
Visitor* up = new UpVisitor(); 
Visitor* down = new DownVisitor(); 
base->accept(up); 
base->accept(down); 

現在我的目標是使用派生訪問中沒有專業;不幸的是,訪問是一種虛擬的方法,所以我不能模板它

+0

你使用什麼編譯器?我只是將您的示例代碼提供給Visual C++ 2010,並且它非常高興地編譯,除了抱怨std :: to_string無法處理模板參數參數類型。我在你的示例代碼中看不到任何理由,爲什麼它會抱怨一個不完整的類型,因爲你不會錯過爲單一的純虛函數提供實現。 –

+0

@MthetheWWalton:「我使用gcc 4.5。」但是,指出編譯器消息引用的行總是很好的。我不想在瀏覽器中計算31行。 – sbi

+0

@sbi doh,我一定忘記了當我給編譯器提供代碼時。不過,我不認爲那種特殊類型的錯誤是GCC和VC++不同意的。 –

回答

1

您的Derived類不能使用Visitor,因爲它尚未定義(它只是前向聲明,因此是一個不完整的類型)。

您可以通過將Visitor定義爲Derived之前的定義來修復編譯錯誤。您還需要定義Visitor之前前瞻性聲明Derived

template <class T> class Derived; 

class Visitor { 
public: 
    virtual void visit(Derived<string> *e) = 0; 
}; 

template <class T> 
class Derived : public Base { 
    //.... can call Visitor methods here ... 
}; 
9

從現代C++ - 設計泛型編程和設計模式應用 - 安德烈Alexandrescu的

#include <iostream> 

class BaseVisitor 
{ 
    public: 
     virtual ~BaseVisitor() {}; 
}; 

template <class T, typename R = int> 
class Visitor 
{ 
    public: 
     virtual R visit(T &) = 0; 
}; 

template <typename R = int> 
class BaseVisitable 
{ 
    public: 
     typedef R ReturnType; 
     virtual ~BaseVisitable() {}; 
     virtual ReturnType accept(BaseVisitor &) 
     { 
      return ReturnType(0); 
     } 
    protected: 
     template <class T> 
     static ReturnType acceptVisitor(T &visited, BaseVisitor &visitor) 
     { 
      if (Visitor<T> *p = dynamic_cast< Visitor<T> *> (&visitor)) 
      { 
       return p->visit(visited); 
      } 
      return ReturnType(-1); 
     } 

     #define VISITABLE() \ 
      virtual ReturnType accept(BaseVisitor &v) \ 
       { return acceptVisitor(*this, v); } 
}; 


/** example of use */ 
class Visitable1 : public BaseVisitable<int> 
{ 
    /* Visitable accept one BaseVisitor */ 
    public: 
     VISITABLE(); 
}; 

class Visitable2 : public BaseVisitable<int> 
{ 
    /* Visitable accept one BaseVisitor */ 
    public: 
     VISITABLE(); 
}; 

class VisitorDerived : public BaseVisitor, 
     public Visitor<Visitable1, int>, 
     public Visitor<Visitable2, int> 
{ 
    public: 
     int visit(Visitable1 & c) 
     { 
      std::cout << __PRETTY_FUNCTION__ << std::endl; 
     } 
     int visit(Visitable2 & c) 
     { 
      std::cout << __PRETTY_FUNCTION__ << std::endl; 
     } 
}; 

int main(int argc, char **argv) 
{ 
    VisitorDerived visitor; 
    Visitable1 visitable1; 
    Visitable2 visitable2; 

    visitable1.accept(visitor); 
    visitable2.accept(visitor); 
} 

可以避免與CRTP模式類似的dynamic_cast :

#include <iostream> 

class BaseVisitor 
{ 
    public: 
     virtual ~BaseVisitor() {}; 
}; 

template <class T> 
class Visitor 
{ 
    public: 
     virtual void visit(T &) = 0; 
}; 

template <class Visitable> 
class BaseVisitable 
{ 
    public: 
     template <typename T> 
     void accept(T & visitor) 
     { 
      visitor.visit(static_cast<Visitable &>(*this)); 
     } 
}; 

/** example of use */ 
class Visitable1 : public BaseVisitable<Visitable1> 
{ 
}; 

class Visitable2 : public BaseVisitable<Visitable2> 
{ 
}; 

class VisitorDerived : public BaseVisitor, 
         public Visitor<Visitable1>, 
         public Visitor<Visitable2> 
{ 
    public: 
     void visit(Visitable1 & c) 
     { 
      std::cout << __PRETTY_FUNCTION__ << std::endl; 
     } 
     void visit(Visitable2 & c) 
     { 
      std::cout << __PRETTY_FUNCTION__ << std::endl; 
     } 
}; 

int main(int argc, char **argv) 
{ 
    VisitorDerived visitor; 
    Visitable1 visitable1; 
    Visitable2 visitable2; 

    visitable1.accept<VisitorDerived>(visitor); 
    visitable2.accept<VisitorDerived>(visitor); 
} 
+0

完全一致我覺得它有點複雜;是否有可能避免dynamic_cast? – codablank1

+1

是的,您可以使用CRTP模式,例如: –

+0

您將如何擴展它以覆蓋層次結構,例如: DerivedVisitable1,同時保持static_cast?是否可以不改變爲循環實施? –