Jef*_*eff 8 c++ oop visitor-pattern dynamic-dispatch
访问者模式是在C++中完成方法参数类型识别(在参数上有效单一调度,而不是成员的类)的最快方法吗?我可能知道我要来调用尚未知亚型的元素的确切方法(S),所以不可避免地使更多的虚拟方法调用就像V::visit(A *)
在A::accept(V &v) { v.visit(this); }
是不可取的.
// Is the Visitor pattern recommended here? (E inherits D inherits B.)
class Foo {
public:
virtual void visit(B *) { result = 3; }
virtual void visit(D *) { result = 4; }
virtual void visit(E *) { result = 5; }
private:
int result;
}; // class Foo
// Need to add generic interface to B and its children ...
class B {
public:
virtual void accept(class Foo &f) { f.visit(this); }
}; // class B
Run Code Online (Sandbox Code Playgroud)
我想要功能上等同于以下但具有O(1)成本的东西,这是使用dynamic_cast <>或typeid()梯子无法实现的AFAIK,因为std::type_info
它不能是constexpr/switchable.
// O(n) search cost might get nasty with bigger hierarchies.
int foo(B *b) {
if (typeid(b) == typeid(B *)) { return 1; }
if (typeid(b) == typeid(D *)) { return 2; }
if (typeid(b) == typeid(E *)) { return 3; }
return -1;
}
Run Code Online (Sandbox Code Playgroud)
我有什么选择?感谢您的建议!
编辑:更改了示例代码以通过字段提供结果,因此不同方法类型不需要多个签名.谢谢,莫里斯!
最终决定:除了不喜欢访问者模式的强制性双重调度成本之外,我还想避免重载的界面臃肿foo()
,但我认为没有一个已知的干净模式来做到这一点.我最终只做了直接的静态重载,并称它为一天.无论如何,我想在函数中封装重载可能是一个可疑的目标.谢谢,莫里斯回应.
事实上,接口不需要重复。访问者的子类可以处理操作的细节。在你的情况下:
class Visitor {
virtual void visit(B*) = 0;
virtual void visit(D*) = 0;
virtual void visit(E*) = 0;
}
class Foo: public Visitor {
private:
int result;
public:
void visit(B*) { result = 3; }
void visit(D*) { result = 4; }
void visit(E*) { result = 5; }
int apply(A* a) {
a->accept(this);
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
因此,每个类中只需要一个accept()方法。
我能想到的访问者模式的所有替代方案都涉及某种运行时搜索,所以是的,恕我直言,访问者模式是最快的方法。
归档时间: |
|
查看次数: |
563 次 |
最近记录: |