我需要编写一个实现访问者设计模式的程序。问题是基本访问者类是模板类。这意味着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();
}
答案 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中的foo
和bar
指针保留两个条目,并且只需检查类定义即可完美地定义vtable。使用模板化函数无法实现这一点。