Показать сообщение отдельно
  (#15 (permalink)) Старый
michael michael вне форума
Member
michael is on a distinguished road
 
Сообщений: 983
Сказал(а) спасибо: 0
Поблагодарили 0 раз(а) в 0 сообщениях
Регистрация: 08.08.2003
По умолчанию 26.02.2007, 17:56

Q: Как сделать коллбэк, если функции принадлежат к разным классам?

A2:
В объектно-ориентированном стиле лучше всего использовать абстрактный callback-интерфейс:
Код:
class ICallback //abstract
{
public:
    virtual void notify() = 0;

protected:
    ~ICallback() {}
};
Класс, который реализует вызов callback-функции, хранит у себя не указатель на функцию, как это обычно делается, а указатель на интерфейс ICallback:
Код:
class A
{
public:
    void set_callback( ICallback* _object ) { _remote_object = _object; }
    // ...
    void func();
    // ...
private:
    ICallback* _remote_object;
};

void A::func()
{
    // ...
    if ( _remote_object != NULL )
        _remote_object->notify();
}
Класс, нуждающийся в уведомлении от класса A, наследуется от ICallback и реализует метод notify():
Код:
class B : public ICallback
{
public:
    B( A& a ) { a.set_callback( this ); } 
private:
    virtual void notify();
    // ...
};

void B::notify()
{
    // Реагируем на сообщение от класса A.
}
Преимущество такого подхода заключается в независимости интерфейса класса A от класса B. Он уже не нуждается в ссылке на класс B в callback-указателе, т.е. реализовать callback можно также в любом другом классе. Кроме того можно использовать интерфейсы с несколькими callback-функциями, а также можно добавить в callback-интерфейс указатель на свой класс для организации списка вызова.
Например:
Код:
class ICallbackInsertRemove //abstract
{
public:
    virtual void inserted( unsigned disk_number ) = 0;
    virtual void removed( unsigned disk_number ) = 0;

    ICallbackInsertRemove* next;

protected:
    ICallbackInsertRemove() : next( NULL ) {}
    ~ICallbackInsertRemove() {}
};
Организация вызова примерно следующая:
Код:
void A::func()
{
    // ...
    for ( ICallbackInsertRemove* ro = _remote_object; ro != NULL; ro = ro->next )
        ro->inserted( disk ); // или, например, ro->removed( disk )
}
Ну и, разумеется, для списка нужно доработать функцию set_callback() и, возможно, добавить функцию remove_callback().
Ответить с цитированием