2010-05-30 72 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