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 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
The output I want is:
Field_String accepting visitor.
Visiting a Field_String object
My two questions:
visit
method in the
descendent Visitor not executed?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:
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.
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);
}
};