Можно ли создать диспетчер вызова метода в C ++? - PullRequest
5 голосов
/ 23 марта 2009

Рассмотрим следующий код:

struct X {
  void MethodX() {
    ...
  }
};

struct Y {
  void MethodY() {
    ...
  }
};

void test () {
  X x;
  Y y;
  Dispatcher d;
  d.Register("x", x, &X::MethodX);
  d.Register("y", y, &Y::MethodY);
  d.Call("x");
  d.Call("y");
}

Вопрос в том, как реализовать Dispatcher. Я не возражаю против того, что X и Y могут наследовать от чего-то, но Dispatcher должен разрешать дальнейших клиентов (не только X и Y) И я хотел бы избежать указателей void *, если это возможно:)

Ответы [ 4 ]

5 голосов
/ 23 марта 2009

Посмотрите на boost :: function , она делает это.

2 голосов
/ 23 марта 2009

Чтобы избежать повышенного использования и реализовать свой собственный, вы можете взглянуть на книгу http://en.wikipedia.org/wiki/Modern_C%2B%2B_Design

В книге описана библиотека Loki с хорошим объяснением того, как сделать свой ум достаточно умным для своего функтора.

class Dispather
{
public:
    typedef boost::function< void ( void ) > FunctionT;

    void Register( const std::string& name, FunctionT function )
    {
        registered_[ name ] = function;
    }

    void Call( const std::string& name )
    {
        RegisterdFunctionsT::const_iterator it =
            registered_.find( name );

        if ( it == registered_.end() )
            throw std::logic_error( "Function is not registered" );

        (it->second)();
    }

private:
    typedef std::map< std::string, FunctionT > RegisterdFunctionsT;
    RegisterdFunctionsT registered_;

};

int main()
{
    X x;
    Y y;

    Dispather d;
    d.Register( "x", boost::bind( &X::MethodX, &x ) );
    d.Register( "y", boost::bind( &Y::MethodY, &y ) );

    d.Call( "x" );
    d.Call( "y" );

    return 0;
}
1 голос
/ 23 марта 2009

Посмотрите на эту бумагу:

http://www.oopweb.com/CPP/Documents/FunctionPointers/Volume/CCPP/functor/functor.html

Он реализует функтор на основе шаблонов в C ++. void * используется под капотами, но все это безопасно для типов, потому что оно обернуто шаблонными функциями, которые создают и разворачивают void *. Это сделало бы реализацию этого легкой. Он поддерживает множество стилей вызова, которые обычные указатели на методы не поддерживают (например, вы можете передать функцию, возвращающую что-то как функтор, возвращающий void, и он автоматически игнорирует возвращаемое значение)

1 голос
/ 23 марта 2009

У меня есть похожий ответ здесь , но ответ Николая ближе к тому, что вам нужно.

...