开发者

Visitor: adding more types via inheritance

I want to expand a declared Visitor through inheritance and have the run-time environment search the descendents of the Visitor for the correct method to execute. I can have this in C#, but I'm looking to use it in C++. I tried the following code in g++ and the descendent method is not called; only the method for the base class is called.

#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;
}

I get the following output:

# g++ --version
g++ (GCC) 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)
Copyright (C) 2004 Free Software 开发者_StackOverflowFoundation, 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

The output I want is:

Field_String accepting visitor.
Visiting a Field_String object

My two questions:

  1. Why is the visit method in the descendent Visitor not executed?
  2. How do I execute the visit method in the descendent Visitor using polymorphism?

Note: The objective is to reduce the classes specified in a Visitor class, by using inheritance and allowing for the cases that may not use all of the classes specified in the Visitor.

Note: This is not double dispatch, but extended dispatch.


You cannot do that in C++ (can you really do it in C# without reflection?) On the particular questions:

  1. The compiler resolves the function overload to use based on the static type of the reference, and the final overrider of that function based on the dynamic type of the object.

  2. You need to provide all of the different overloads in the base class. If you cannot do it, you can do nasty things like dynamic_cast's to try and determine whether the Visitor received has support for that particular field, but I would avoid it at all costs. dispatch*.

Since the different field types are not being used polymorphically (or at least it does not seem like it, since the accept_visitor functions are not virtual), why don't you accept the concrete visitor type?

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


Is there a reason you have to derive a second Visitor_Field_String virtual class type from you Visitor virtual class? For instance, if you define your base Visitor and Full_Visitor classes like this:

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;
    }
};

you'll get the functionality you're looking for. The problem with what you're trying to-do is that the class-type that fs.accept_visitor(visitor) is being polymorphically cast to is a Visitor object-type which only has virtual void visit(Field& f) defined. So calling visit() on a class of type Visitor, without some type of additional cast to a Visitor_Field_String class-type inside your accept_visitor() functions will not refer to the additional overloaded versions of your visit() function as they're defined in the derived class.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜