2010-05-30 73 views
15

我需要編寫一個實現訪問者設計模式的程序。問題是基礎訪問者類是一個模板類。這意味着BaseVisited :: accept()將一個模板類作爲參數,並且由於它使用'this',我需要'this'指向該對象的正確運行時實例,所以它也需要是虛擬的。
我想知道是否有解決此問題的方法。需要虛擬模板成員解決方法

template <typename T> 
class BaseVisitor { 
    public: 
    BaseVisitor(); 
    T visit(BaseVisited *visited); 
    virtual ~BaseVisitor(); 
} 


class BaseVisited { 
    BaseVisited(); 
    template <typename T> 
    virtual void accept(BaseVisitor<T> *visitor) { visitor->visit(this); }; // problem 
    virtual ~BaseVisited(); 
} 
+1

這是什麼問題? – 2010-05-30 18:50:37

+2

它不會編譯。 http://stackoverflow.com/questions/2354210/template-member-function-virtual – yurib 2010-05-30 18:54:24

+2

編譯器不會接受虛擬函數中的模板。 – Puppy 2010-05-30 18:54:38

回答

16

你應該做的是分開BaseVisitor。

class BaseVisited; 
class BaseVisitorInternal { 
public: 
    virtual void visit(BaseVisited*) = 0; 
    virtual ~BaseVisitorInternal() {} 
}; 
class BaseVisited { 
    BaseVisited(); 
    virtual void accept(BaseVisitorInternal* visitor) { visitor->visit(this); } 
}; 
template<typename T> class BaseVisitor : public BaseVisitorInternal { 
    void visit(BaseVisited* visited); 
}; 

如果您需要BaseVisited的派生類過於模板,並通過他們的正確類型/重載參觀,你是官方正式宣佈死亡。

+0

你打敗了我! :-) – 2010-05-30 19:08:31

+3

基本上,這是[類型擦除](http://stackoverflow.com/questions/2354210/template-member-function-virtual/2354671#2354671)。 – sbi 2010-05-30 19:54:47

+0

我想我可能會正式死亡...... :-P – NargothBond 2017-10-06 14:49:58

4

我想出了比DeadMG略有不同:

class BaseVisited; 

class IVisitor { 
    public: 
    virtual void visit(BaseVisited *visited) = 0; 
    virtual ~IVisitor(); 
}; 

template <typename T> 
class BaseVisitor : public IVisitor { 
    public: 
    BaseVisitor(); 
    virtual void visit(BaseVisited *visited); 
    virtual ~BaseVisitor(); 
    virtual T result(); 
}; 


class BaseVisited { 
    public: 
    BaseVisited(); 
    virtual void accept(IVisitor *visitor) { visitor->visit(this); }; 
    virtual ~BaseVisited(); 
}; 

礦有一個額外的result()成員函數,可以讓你找回上次訪問的結果。

+0

我不認爲這會起作用 – 2016-04-22 04:17:14

4

您不能聲明/定義模板化的虛擬功能。原因是當編譯器看到基類定義時必須知道虛擬調度機制,但模板是按需編譯的。

對於常見的vtable實現,問題是編譯器必須爲虛擬函數保留的條目數量是未定義的(該類型有多少個不同的實例可以存在?),它們的順序也是如此。如果聲明類:

class base { 
public: 
    virtual void foo(); 
    virtual int bar(); 
}; 

編譯器可以在虛函數表的指針vtable中保留兩個條目,以foobar和虛函數表是完全由剛剛檢查類定義來定義。這是模板化功能無法實現的。

+0

我知道它不可能,我明白爲什麼,我的問題是要找到一個不涉及模板虛擬功能的解決方案。 儘管如此。 – yurib 2010-05-30 19:50:21

+0

@Yurib:你想要一個解決方案,但你沒有說明你的問題 - 我要求對這個問題發表評論:你真正想達到的是什麼。你只問過一個不起作用的潛在解決方案,而不是最初的問題。 – 2010-05-31 07:06:44