2010-10-27 1 views
2

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

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

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

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

+0

Какой выходной сигнал? Любые ошибки/предупреждения компилятора? –

+1

Я смущен, что «семантика интерфейса» связана с тем, что вы здесь делаете. Почему бы вам просто не использовать чистые абстрактные базовые классы и виртуальные функции? Смотрите: http://www.parashift.com/c++-faq-lite/abcs.html#faq-22.4 –

+0

Хорошо, теперь мне ясно, что я собрал несколько вещей и дал недостаточно подробностей в моем примере. То, что я действительно делаю, использует 'boost :: signal' для вызова различных зарегистрированных обработчиков. Чтобы использовать более откровенный пример, допустим, у меня есть абстрактный класс EventListener с методами 'handleFooEvent',' handleBarEvent' и 'handleBazEvent'. Я хотел бы зарегистрировать экземпляр «EventListener» и связать эти методы 'handle * Event' с каждым слотом. –

ответ

3

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>, так как boost::bind и вывод аргумента заботиться о тех, кто для вас.)

0

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

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

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

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