混合使用模板和非模板访问者方法



目前我正在学习访问者模式并尝试各种想法。下面是我当前设置的代码,我希望它能以某种方式发挥作用。

我想要两个访问者,一个分别计算RedBlu的实例,另一个计算任何东西(可以假设它是Color(

当然,这可以通过简单地实现与第一个访问者类似的第二个访问者来解决,但是不使用单独的变量进行计数,而只使用一个变量。然而,我认为这是不必要的——例如,如果我有很多不同的颜色,代码就会非常重复:访问者中的所有函数都是相同的,它们只会增加一个变量。当然,有一种更简单的方法,但怎么做呢?根据标准的访问者模式,我必须为每个颜色类实现一个访问函数,因此这似乎不是正确的方法。

有人会如何解决这个问题?

#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::eyen";
}
};
class Blu: public Color
{
public:
/*virtual*/
void accept(Visitor*);
void sky()
{
std::cout << "Blu::skyn";
}
};
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();
}

不幸的是,虚拟方法和模板方法无法匹配。

我的意思是。。。如果您的基类Visitor需要

virtual void visit(Red*) = 0;
virtual void visit(Blu*) = 0;

在派生类中实现两个虚拟方法,不能用单个模板方法来解决这一义务

template<class C>
void visit(C* c)
{
++num_of_colours;
}

您必须编写两种方法,绝对不是模板,并具有确切的签名。也许还可以添加override,以降低出错的风险。

void visit (Red * r) override
{ ++num_of_colours; }
void visit (Blu * b) override
{ ++num_of_colours; }

显然,您可以定义一个模板方法(可能有另一个名称,但如果您愿意,也可以定义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); }

通过这种方式,您可以在单个模板方法中实现访问者的逻辑,并通过所有虚拟方法调用它

为什么不使用映射并在颜色中添加一些函数作为标识符呢?

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()]++;
}
};

最新更新