[英]Mix template and non-template visitor methods
Currently I am learning about the Visitor Pattern and try out various ideas. 目前,我正在学习访客模式并尝试各种想法。 Below I have the code of my current setup, which I would like to get functioning somehow. 下面有我当前设置的代码,我想以某种方式使其运行。
I would like to have two visitors, one that counts instances of Red
and Blu
separately and one that counts anything (one can assume, it's a Color
) 我想有两个访问者,一个来分别计算Red
和Blu
实例,另一个来计算任何东西(一个可以假设,它是Color
)。
This is of course solvable by simply implementing the second visitor analogously to the first one, however not using separate variables for counting, but just one. 当然,这可以通过简单地实现类似于第一个访客的第二个访客来解决,但是不使用单独的变量进行计数,而只是使用一个变量。 I think however this is unnecessary - if I had for example many, many different colours, the code would be very repetitive: All functions in that visitor would be same, they would simply increment one variable. 但是我认为这是不必要的-例如,如果我有很多不同的颜色,则代码将是非常重复的:该访问者中的所有函数都是相同的,它们只会增加一个变量。 Surely, there is an easier way, but how? 当然,有一种更简单的方法,但是如何? According to the standard Visitor Pattern I have to implement for every color class a visit functions, thus this does not seem to be the right approach. 根据标准的访问者图案,我必须为每种颜色类别实现访问功能,因此这似乎不是正确的方法。
How would someone solve this problem? 有人将如何解决这个问题?
#include <iostream>
class Color
{
public:
virtual void accept(class Visitor*) = 0;
};
class Red: public Color
{
public:
/*virtual*/
void accept(Visitor*);
void eye()
{
std::cout << "Red::eye\n";
}
};
class Blu: public Color
{
public:
/*virtual*/
void accept(Visitor*);
void sky()
{
std::cout << "Blu::sky\n";
}
};
class Visitor
{
public:
virtual void visit(Red*) = 0;
virtual void visit(Blu*) = 0;
};
class CountVisitor: public Visitor
{
public:
CountVisitor()
{
m_num_red = m_num_blu = 0;
}
/*virtual*/
void visit(Red*)
{
++m_num_red;
}
/*virtual*/void visit(Blu*)
{
++m_num_blu;
}
void report_num()
{
std::cout << "Reds " << m_num_red << ", Blus " << m_num_blu << '\n';
}
private:
int m_num_red, m_num_blu;
};
class TemplateVisitor: public Visitor
{
public:
TemplateVisitor() : num_of_colours(0) {}
/*virtual*/
template<class C>
void visit(C* c)
{
++num_of_colours;
}
void report_num()
{
std::cout << "Colours " << num_of_colours << '\n';
}
private:
int num_of_colours;
};
void Red::accept(Visitor *v)
{
v->visit(this);
}
void Blu::accept(Visitor *v)
{
v->visit(this);
}
int main()
{
Color *set[] =
{
new Red, new Blu, new Blu, new Red, new Red, nullptr
};
CountVisitor count_operation;
TemplateVisitor template_visitor;
for (int i = 0; set[i]; i++)
{
set[i]->accept(&count_operation);
set[i]->accept(&template_visitor);
}
count_operation.report_num();
template_visitor.report_num();
}
Unfortunately, virtual methods and template methods can't match. 不幸的是,虚拟方法和模板方法无法匹配。
I mean... if your base class Visitor
require 我的意思是...如果您的基层Visitor
需要
virtual void visit(Red*) = 0;
virtual void visit(Blu*) = 0;
the implementation of two virtual methods in derived classes, you can't solve this obligation with a single template method 派生类中两个虚拟方法的实现,您不能使用单个模板方法解决此义务
template<class C>
void visit(C* c)
{
++num_of_colours;
}
You have to write two methods, absolutely not template, with the exact signature. 您必须编写两种具有完全签名的方法,绝对不是模板。 Maybe adding also override
, to reduce the risk of mistakes. 也许还添加了override
,以减少出错的风险。
void visit (Red * r) override
{ ++num_of_colours; }
void visit (Blu * b) override
{ ++num_of_colours; }
Obviously you can define a template method (maybe with another name, but also visit()
if you want) that is called by both virtual overrided methods 显然,您可以定义两个虚拟重写方法都调用的模板方法(可能使用其他名称,也可以根据需要visit()
)。
template <typename C>
void visit (C * c)
{ ++num_of_colours; }
void visit (Red * r) override
{ visit<Red>(r); }
void visit (Blu * b) override
{ visit<Blu>(b); }
This way, you can implement the logic of the visitor in a single template method and call it by all virtual methods 这样,您可以在单个模板方法中实现访问者的逻辑,并通过所有虚拟方法进行调用
Why not just use a map and add some function to color to use as an identifier? 为什么不只使用地图并为颜色添加一些功能以用作标识符?
class Color
{
public:
virtual void accept(class Visitor*) = 0;
virtual std::string color_name() = 0;
};
class Visitor
{
public:
virtual void visit(Color* c);
};
class CountVisitor: public Visitor
{
std::unordered_map<std::string, int> map;
public:
/*virtual*/
void visit(Color* c)
{
map[c.color_name()]++;
}
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.