需要虚拟模板成员解决方法

时间:2010-05-30 18:46:44

标签: c++ templates virtual visitor

我需要编写一个实现访问者设计模式的程序。问题是基本访问者类是模板类。这意味着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();
}

3 个答案:

答案 0 :(得分:17)

您应该做的是将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的派生类并传递正确的类型/重载来访问,那么你已经正式死了。

答案 1 :(得分: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()成员函数,可以让你检索上次访问的结果。

答案 2 :(得分:4)

您无法声明/定义模板化虚拟函数。原因是当编译器看到基类定义时必须知道虚拟调度机制,但模板是按需编译的。

使用常见的vtable实现时,问题是编译器必须为虚函数保留的条目数是未定义的(可以有多少种类型的不同实例?),以及它们的顺序。如果你声明了这个类:

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

编译器可以在vtable中为vtable中的foobar指针保留两个条目,并且只需检查类定义即可完美地定义vtable。使用模板化函数无法实现这一点。