Двойная диспетчеризация не удалась для InputMap в C ++ - коды сведены к простоте - PullRequest
1 голос
/ 14 сентября 2011

Здравствуйте, в одном из моих текущих проектов я хочу реализовать InputMap.Итак, у меня есть абстрактный ввод

//Input.h
namespace INPUT {
class InputMap;
class Input {
public:
    Input();
    virtual ~Input();
    virtual void Dispatch( InputMap * pMap ) = 0;
};
}

и InputMap

//InputMap.h
namespace INPUT {
class InputMap {
public:
    InputMap();
    virtual void HandleInput( INPUT::Input & anInput ) {
    }
    virtual ~InputMap();
};
}

, пока что все хорошо - здесь нет никакой функциональности.Теперь я извлекаю свой первый реальный вход из моего абстрактного входного класса:

//StringInput.h
#include "Input.h"
#include "InputMap.h"
#include <string>

class StringInput : INPUT::Input {
public:
    StringInput();
    virtual ~StringInput();
    void Dispatch(INPUT::InputMap * pMap)
    {
        pMap->HandleInput( *this );
    }
    void SetMessage(std::string message);
    std::string GetMessage() const;
private:
     std::string m_message;
};

, и вот мой производный InputMap

//MyInputMap.h
#include "InputMap.h"
#include "StringInput.h"

class MyInputMap: public INPUT::InputMap {
public:
    MyInputMap();
    void HandleInput( StringInput & anInput );
    void HandleInput( INPUT::Input & anInput );
    virtual ~MyInputMap();
};

, а вот тест:

//main.cpp
MyInputMap map;
StringInput input;
input.SetMessage("Test");
input.Dispatch(&map);

конечно, я ожидаю, что input.Dispatch(&map) вызывает map.HandleInput(StringInput input), но, к сожалению, всегда вызывается обработчик по умолчанию.Я неправильно запрограммировал этот шаблон?Спасибо, ребята, я смотрю свой код вечно, но я его не вижу.

Ответы [ 2 ]

2 голосов
/ 14 сентября 2011

Вы должны прочитать о шаблоне Visitor .

По сути, проблема в том, что виртуальные функции статически связаны (иронично), поэтому решение состоит в том, чтобы объявить все HandleInput (длякаждый тип Input) в InputMap.

class InputMap {
public:
    InputMap();
    virtual void HandleInput(StringInput&) = 0;
    virtual void HandleInput(IntInput&) = 0;
    virtual ~InputMap();
};

Примечание: соглашение состоит в том, чтобы использовать чисто виртуальные методы, чтобы ни один производный класс не забывал переопределить один.

Конечно, это вызывает проблему зависимостей.К счастью, вы можете заранее объявить «настоящие» типы ввода в заголовке, содержащем InputMap.

Существуют более сложные варианты (поиск Acyclic Visitor), но вам это сейчас не нужно:)

0 голосов
/ 14 сентября 2011

Функция поиска и разрешения перегрузки выполняется для статического типа .Поэтому, когда вы говорите pMap->HandleInput(*this) в StringInput::Dispatch(), это всегда находит перегрузку InputMap::HandleInput(Input &), потому что pMap имеет статический тип InputMap.Затем он динамически отправляется на переопределение MyInputMap::HandleInput(Input &).

. Один из способов преодолеть это - добавить динамическую диспетчеризацию в (уникальную) функцию HandleInput(), которая определяет динамический тип аргумента во время выполнения.

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