访问者:通过继承添加更多类型

时间:2011-06-13 18:34:06

标签: c++ inheritance design-patterns visitor

我想通过继承扩展声明的访问者,并让运行时环境搜索访问者的后代,以便执行正确的方法。我可以在C#中使用它,但我希望在C ++中使用它。我在g ++中尝试了以下代码,并且没有调用后代方法;只调用基类的方法。

#include <iostream>
using namespace std;

struct Field; // Forward declaration

struct Visitor
{
    virtual void visit(Field& f) = 0; // Visits Field objecs and objects derived from Field.
};

struct Field_String;

struct Visitor_Field_String : public Visitor
{
    // Extend the Visitor by specifying a visitation
    //     for Field_String
    virtual void visit(Field_String& fs) = 0;
};

struct Field
{
    void accept_visitor(Visitor& v)
    {
        cout << "Field accepting visitor.\n";
        v.visit(*this);
    }
};

struct Field_String : public Field
{
    void accept_visitor(Visitor& v)
    {
        cout << "Field_String accepting visitor.\n";
        v.visit(*this);  // Line 1
    }
};

struct Full_Visitor : Visitor_Field_String
{
    void visit(Field& f)
    {
        cout << "Visiting a Field object\n";
        return;
    }
    void visit(Field_String& fs)
    {
        cout << " Visiting a Field_String object\n";
        return;
    }
};


int main(void)
{
    Field_String fs;
    Full_Visitor visitor;
    fs.accept_visitor(visitor);
    return 0;
}

我得到以下输出:

# g++ --version
g++ (GCC) 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# g++ -o virtual_visitor.exe virtual_visitor.cpp
# ./virtual_visitor.exe
Field_String accepting visitor.
Visiting a Field object

我想要的输出是:

Field_String accepting visitor.
Visiting a Field_String object

我的两个问题:

  1. 为什么visit方法在 后代访客没被执行?
  2. 如何执行visit方法 在后代访客使用 多态性?
  3. 注意:目标是通过使用继承并允许可能不使用访问者中指定的所有类的情况来减少Visitor类中指定的类。

    注意:这不是双重调度,而是扩展调度。

2 个答案:

答案 0 :(得分:1)

您是否有必要从Visitor_Field_String虚拟类派生第二个Visitor虚拟类类型?例如,如果您定义基本VisitorFull_Visitor类,请执行以下操作:

struct Visitor
{
    virtual void visit(Field& f) = 0;
    virtual void visit(Field_String& fs) = 0;
};

struct Full_Visitor : public Visitor
{
    void visit(Field& f)
    {
        cout << "Visiting a Field object\n";
        return;
    }
    void visit(Field_String& fs)
    {
        cout << " Visiting a Field_String object\n";
        return;
    }
};

您将获得您正在寻找的功能。您尝试执行的操作的问题是fs.accept_visitor(visitor)被多态转换为的类类型是Visitor对象类型,只定义了virtual void visit(Field& f)。因此,对visit()类型的类调用Visitor,而Visitor_Field_String函数中没有对accept_visitor()类类型进行某种类型的额外强制转换将不会引用其他重载版本你的visit()函数在派生类中的定义。

答案 1 :(得分:1)

你不能用C ++做到这一点(你真的可以在没有反思的C#中做到吗?)关于特定的问题:

  1. 编译器根据引用的静态类型解析要使用的函数重载,并根据对象的动态类型解析该函数​​的最终覆盖。

  2. 您需要在基类中提供所有不同的重载。如果你不能这样做,你可以做一些讨厌的事情,比如dynamic_cast来尝试确定收到的Visitor是否支持该特定字段,但我会不惜一切代价避免它。 调度*

  3. 由于不同的字段类型没有被多态使用(或者至少它看起来不像,因为accept_visitor函数不是虚拟的),为什么不接受具体的访问者类型?

    struct Field_String : Field
    {
        void accept_visitor(Visitor_Field_String& v)
        {
            cout << "Field_String accepting visitor.\n";
            v.visit(*this);
        }
    };