«Интерфейс» как семантика с boost :: bind - PullRequest
2 голосов
/ 28 октября 2010

Я хотел иметь что-то вроде семантики интерфейса Java с C ++. Сначала я использовал boost::signal для обратного вызова явно зарегистрированных функций-членов для данного события. Это сработало очень хорошо.

Но затем я решил, что некоторые пулы обратных вызовов функций были связаны, и имело смысл абстрагировать их и зарегистрировать для всех связанных обратных вызовов экземпляра одновременно. Но что я узнал, так это то, что специфическая природа boost::bind и / или принятие значения this, казалось, делали этот разрыв. Или, возможно, это просто тот факт, что объявление метода add_listener(X &x) изменило код, сгенерированный boost::bind.

Я очень грубо понимаю, почему возникла проблема, и я думаю, что она, вероятно, работает правильно в соответствии с ее дизайном. Мне любопытно: что должен я сделал вместо этого? Конечно, есть верный способ сделать это.

Вот пример кода:

#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <iostream>

using namespace std;

struct X;
struct Callback
{
    virtual void add_listener(X &x) = 0;
};

struct X
{
    X() {}
    X(Callback &c) {  c.add_listener(*this); }
    virtual void go() { cout << "\t'" << __PRETTY_FUNCTION__ << "'" << endl; }
};

struct CallbackReal : public Callback
{
    virtual void add_listener(X &x)
    {
        f = boost::bind<void>(boost::mem_fn(&X::go), x);
    }

    void go() { f(); }

    boost::function<void (void)> f;
};


struct Y : public X
{
    Y() {}

    Y(Callback &c) {  c.add_listener(*this); }
    virtual void go() { cout << "\t'" << __PRETTY_FUNCTION__ << "'" << endl; }
};


int main(void)
{
    CallbackReal c_x;
    CallbackReal c_y;

    X x(c_x);
    Y y(c_y);

    cout << "Should be 'X'" << endl;
    boost::bind<void>(boost::mem_fn(&X::go), x)();

    cout << "Should be 'Y'" << endl;
    boost::bind<void>(boost::mem_fn(&X::go), y)();

    cout << "------------------" << endl;

    cout << "Should be 'X'" << endl;
    c_x.go();
    cout << "I wish it were 'Y'" << endl;
    c_y.go();

    return 0;
}

Хорошо, я не описал проблему полностью. Название вводит в заблуждение.

О, чувак. Downvote это. Я, очевидно, плохо описал проблему, и я думаю, что в конечном итоге это сводится к синтаксической ошибке. (

Ответы [ 2 ]

3 голосов
/ 28 октября 2010

boost::bind принимает параметры по значению и копирует их.Это означает, что

f = boost::bind<void>(boost::mem_fn(&X::go), x);

передаст копию из x, которая отрежет часть Y (если это действительно было Y с самого начала),Чтобы заставить виртуальную диспетчеризацию работать, вам нужно передать указатель на boost::bind:

f = boost::bind(&X::go, &x);

(обратите внимание, что на самом деле вам не нужен mem_fn, или явно писать <void>, поскольку1016 * и вывод аргументов позаботится о тех, кто для вас.)

0 голосов
/ 28 октября 2010

Java-интерфейсы специально не существуют в C ++. Ближе всего можно получить чисто абстрактные базовые классы. Как правило, это достаточно близко.

Остальная часть вашего вопроса не связана с интерфейсами. Java использует шаблон Observer для подключения и отправки событий. Интерфейсная часть слабо связана, потому что наблюдатели обязаны подчиняться определенным интерфейсам (конечно, так как в противном случае вы бы не знали, что вызывать).

Использование boost :: bind для создания функторов на самом деле является абстракцией за пределами интерфейсов и, таким образом, является более общим решением. Паттерн наблюдателя и функторы объединяются в идиому / паттерны сигнал / слот, реализованные в различных библиотеках, таких как boost :: signal, boost :: signal2 и gtk ++. Версия Qt сильно отличается по механике, но схожа по концепции.

Итак, что это значит, чтобы помочь вам понять, что, почему и где? Я бы предложил начать с поиска шаблона Observer и попытаться написать несколько реализаций.

...