- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有五个类与相关访问者:
struct Visitor
{
virtual ~Visitor() = default;
virtual void visit(A&) {}
virtual void visit(B&) {}
virtual void visit(C&) {}
virtual void visit(D&) {}
virtual void visit(E&) {}
};
struct A
{
virtual ~A() = default;
virtual void accept(Visitor& v) { v.visit(*this); }
};
struct B : A { void accept(Visitor& v) override { v.visit(*this); } };
struct C : A { void accept(Visitor& v) override { v.visit(*this); } };
struct D : C { void accept(Visitor& v) override { v.visit(*this); } };
struct E : C { void accept(Visitor& v) override { v.visit(*this); } };
所有实例都将在最大可能的抽象级别上被用户代码看到,因此它们都将被视为A&
。用户代码需要做两类操作:
"I am C"
如果实例恰好是 C
"I am C"
如果实例是 C
类型或其任何子类型(即 D
或 E
)操作 1 的实现非常简单,并且几乎可以在具有适当基础设施的访问者设计模式框外工作:
struct OperationOne : Visitor
{
void visit( C& ) override { std::cout << "I am C" << std::endl; }
};
正如预期的那样,字符串 "I am C"
将只打印一次:
int main( )
{
A a; B b; C c; D d; E e;
std::vector<std::reference_wrapper<A>> vec = { a, b, c, d, e };
OperationOne operation_one;
for (A& element : vec)
{
element.accept(operation_one);
}
}
问题是:对于第二个操作,整个基础设施不再工作,假设我们不想重复 D
和 E
的打印代码嗯:
struct OperationTwo : Visitor
{
void visit( C& ) override { std::cout << "I am C" << std::endl; }
void visit( D& ) override { std::cout << "I am C" << std::endl; }
void visit( E& ) override { std::cout << "I am C" << std::endl; }
};
如果层次结构发生变化并且 D
不再是 C
的子类型,而是例如 A< 的直接子类型,尽管这会起作用
,此代码仍然可以编译,但在运行时不会有预期的行为,这是危险和不可取的。
实现操作 2 的一个解决方案是更改访问者基础结构,以便每个可访问类都将接受的访问者传播到其基类:
struct B : A
{
void accept(Visitor& v) override
{
A::accept( v );
v.visit( *this );
}
};
这样,如果层次结构发生变化,我们将出现编译错误,因为编译器在尝试传播接受的访问者时将不再找到基类。
也就是说,我们现在可以编写第二个操作 visitor,这次我们不需要复制 D
和 E
的打印代码:
struct OperationTwo : Visitor
{
void visit(C&) override { std::cout << "I am C" << std::endl; }
}
正如预期的那样,当使用 OperationTwo
时,字符串 "I am C"
将在用户代码中打印三次:
int main()
{
A a; B b; C c; D d; E e;
vector< reference_wrapper< A > > vec = { a, b, c, d, e };
OperationTwo operation_two;
for ( A& element : vec )
{
element.accept( operation_two );
}
}
但是等等:OperationOne
和OperationTwo
代码是完全一样的!这意味着通过改变第二个操作的基础设施,我们基本上打破了第一个。事实上,现在 OperationOne
也会打印三次字符串 "I am C"
。
要使 OperationOne
和 OperationTwo
无缝协作,可以做些什么?我是否需要将访问者设计模式与另一种设计模式相结合,还是根本不需要使用访问者?
最佳答案
您可以将以下内容作为访问者使用,它将通过重载解决方案进行分派(dispatch):
template <typename F>
struct OverloadVisitor : Visitor
{
F f;
void visit(A& a) override { f(a); }
void visit(B& b) override { f(b); }
void visit(C& c) override { f(c); }
void visit(D& d) override { f(d); }
void visit(E& e) override { f(e); }
};
然后
struct IAmAC
{
void operator()( C& ) { std::cout << "I am C" << std::endl; }
void operator()( A& ) {} // Fallback
};
using OperationTwo = OverloadVisitor<IAmAC>;
关于c++ - 访问者设计模式和多层类层次结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57802933/
我正在尝试将多个水平链接的 Button 和 TextView 垂直链接为 View 集,但仍保持平面 View 层次结构。这是我的初始布局和代码:
到目前为止,我已经在Google BigQuery上训练了几种模型,目前我需要查看模型的外观(即架构,损失函数等)。 有没有办法获取这些信息? 最佳答案 仔细阅读文档后,我可以说该功能尚不存在。我什至
本文实例讲述了PHP实现二叉树深度优先遍历(前序、中序、后序)和广度优先遍历(层次)。分享给大家供大家参考,具体如下: 前言: 深度优先遍历:对每一个可能的分支路径深入到不能再深入为止,而且每个
我是一名优秀的程序员,十分优秀!