【发布时间】:2010-07-15 10:42:48
【问题描述】:
任何人都可以在之前和之后显示示例代码以避免访问者模式代码的向下转换吗?
谢谢。
【问题讨论】:
标签: c++ visitor-pattern
任何人都可以在之前和之后显示示例代码以避免访问者模式代码的向下转换吗?
谢谢。
【问题讨论】:
标签: c++ visitor-pattern
一个简单的、简约的例子。
class Base {};
class Derived1 : public Base {};
class Derived2 : public Base {};
// Some arbitrary function that handles Base.
void
Handle(Base& obj) {
if (...type is Derived1...) {
Derived1& d1 = static_cast<Derived1&>(base);
std::printf("Handling Derived1\n");
}
else if (...type is Derived2...) {
Derived2& d2 = static_cast<Derived2&>(base);
std::printf("Handling Derived2\n");
}
}
这意味着Base 必须有一些类型标签字段,否则您将使用dynamic_cast 来检查每种类型。
// Class definitions
class Visitor;
class Base {
public:
// This is for dispatching on Base's concrete type.
virtual void Accept(Visitor& v) = 0;
};
class Derived1 : public Base {
public:
// Any derived class that wants to participate in double dispatch
// with visitor needs to override this function.
virtual void Accept(Visitor& v);
};
class Derived2 : public Base {
public:
virtual void Accept(Visitor& v);
};
class Visitor {
public:
// These are for dispatching on visitor's type.
virtual void Visit(Derived1& d1) = 0;
virtual void Visit(Derived2& d2) = 0;
};
// Implementation.
void
Derived1::Accept(Visitor& v) {
v.Visit(*this); // Calls Derived1 overload on visitor
}
void
Derived2::Accept(Visitor& v) {
v.Visit(*this); // Calls Derived2 overload on visitor
}
这就是框架。现在你实现了实际的访问者来多态地处理对象。
// Implementing custom visitor
class Printer : public Visitor {
virtual void Visit(Derived1& d1) { std::printf("Handling Derived1\n"); }
virtual void Visit(Derived2& d2) { std::printf("Handling Derived2\n"); }
};
// Some arbitrary function that handles Base.
void
Handle(Base& obj)
{
Printer p;
obj.Accept(p);
}
Accept() 是一个在obj 类型上调度的虚函数(第一次调度)Visit() 的适当重载,因为在Accept() 中您已经知道对象的类型。Visit() 又是一个虚拟函数,根据访问者的类型进行调度(第二次调度)。因为您有双重调度(一个在对象上,另一个在访问者上),所以您不进行任何转换。不利的一面是,每当您向层次结构中添加一个类时,您都必须去更新您的访问者类以添加适当的函数来处理新的子类。
【讨论】:
Handle() 只是一个可以去任何地方(无论在哪里)的任意函数。作为层次结构一部分的派生类必须实现Accept() 并使用自身调用访问者。
wikipedia 示例使用双重调度,没有向下转换。
【讨论】: