Посетитель: добавление большего количества типов через наследование - PullRequest
1 голос
/ 13 июня 2011

Я хочу расширить объявленного посетителя с помощью наследования и сделать так, чтобы среда выполнения выполняла поиск потомков посетителя, чтобы найти правильный метод для выполнения. Я могу иметь это в 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 в потомке посетителя с помощью полиморфизм?

Примечание. Цель состоит в том, чтобы уменьшить количество классов, указанных в классе Visitor, с помощью наследования и учета случаев, в которых могут не использоваться все классы, указанные в Visitor.

Примечание. Это не двойная отправка, а расширенная отправка.

Ответы [ 2 ]

1 голос
/ 13 июня 2011

Вы не можете сделать это в C ++ (вы действительно можете сделать это в C # без размышления?) По конкретным вопросам:

  1. Компилятор разрешает перегрузку функции для использования на основе статическоготип ссылки и окончательное переопределение этой функции в зависимости от динамического типа объекта.

  2. Необходимо обеспечить все различные перегрузки в базовом классе.Если вы не можете этого сделать, вы можете сделать такие неприятные вещи, как dynamic_cast, чтобы попытаться определить, имеет ли полученный Visitor поддержку для этого конкретного поля, но я бы избегал этого любой ценой.dispatch *.

Поскольку различные типы полей не используются полиморфно (или, по крайней мере, это не так, поскольку функции accept_visitor не являются виртуальными), почемуВы принимаете конкретный тип посетителей?

struct Field_String : Field
{
    void accept_visitor(Visitor_Field_String& v)
    {
        cout << "Field_String accepting visitor.\n";
        v.visit(*this);
    }
};
1 голос
/ 13 июня 2011

Есть ли причина, по которой вам нужно получить второй Visitor_Field_String тип виртуального класса от вас Visitor виртуальный класс? Например, если вы определили свои базовые Visitor и Full_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(), поскольку они определены в производном классе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...