c++ - 混合模板和非模板访问者方法

标签 c++ templates design-patterns visitor-pattern

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

我想有两个访问者,一个分别计算 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::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();
}

最佳答案

很遗憾,虚拟方法和模板方法无法匹配。

我的意思是...如果您的基类 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); }

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

关于c++ - 混合模板和非模板访问者方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53751202/

相关文章:

c++ - 尝试从资源加载位图返回 NULL,错误代码为 1813

c++ - streambuf::xsgetn 和状态标志

c++ - 有人知道像 MFC Internals for Qt 这样的书或文档吗?

java 使用 FreeMarker 模板写入文本文件

c# - 如何测试依赖于显示模板的代码?

asp.net - ASP.NET 网络表单和 MVC 基于哪种模式?页面 Controller ,前端 Controller ?

c++ - "Dynamic"没有模板或向下转换的参数类型(?)

C++ 奇怪的 char* 参数问题(不兼容的类型)

C++ 非类型模板参数 : Is typedef of an integral type an integral type?

design-patterns - 设计模式和框架有什么区别?