Многочисленные ошибки компилятора при попытке реализовать шаблон наблюдателя - PullRequest
0 голосов
/ 27 июля 2011

Ранее я опубликовал вопрос о том, как привести функцию-член к указателю функции typedef ( Как использовать указатель функции typedef для регистрации обратного вызова ), и это побудило меня рассмотреть слегка измененное решение: реализация "классического" паттерна наблюдателя.

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

Вот пример, совместимый с sscce, который я вставил на ideone.com (с ошибками компилятора под ним):

#include <set>

typedef int (*CallbackEvent)(const char*, const char*, int);

// Observer interface
class IObserver
{
public: 
    virtual ~IObserver(){}
    virtual int CallMeBack(const char*, const char*, int);
};

class A
{
private:
    std::set<IObserver> observers;
public:
    A(){}
    ~A(){}
    void RegisterObserver(const IObserver& observer)
    {
        observers.insert(observer);
    }

    inline void UnregisterObserver(const IObserver& observer)
    {
        observers.erase(observer);
    }

    void NotifyAll()
    {
        for(std::set<IObserver>::iterator itr = observers.begin(); itr != observers.end(); itr++)
        {
            int z = 3;
            itr->CallMeBack("x","y",z); // <-- This is the part that's not working
        }
    }
};

// Has internal logic to handle the callback
class B : public IObserver
{
private:
    A myA;
public:
    B(A& a)
    {
        myA = a;
        myA .RegisterObserver(*this);
    }
    ~B()
    {
        myA .UnregisterObserver(*this);
    }

    int CallMeBack(const char* x, const char* y, int z)
    {
        return 0;
    }
};

Ошибки компилятора:

prog.cpp: In member function ‘void A::NotifyAll()’:
prog.cpp:38: error: passing ‘const IObserver’ as ‘this’ argument of ‘virtual int IObserver::CallMeBack(const char*, const char*, int)’ discards qualifiers
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_function.h: In member function ‘bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = IObserver]’:
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_tree.h:1141:   instantiated from ‘std::pair<typename std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(const _Val&) [with _Key = IObserver, _Val = IObserver, _KeyOfValue = std::_Identity<IObserver>, _Compare = std::less<IObserver>, _Alloc = std::allocator<IObserver>]’
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_set.h:381:   instantiated from ‘std::pair<typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename _Alloc::rebind<_Key>::other>::const_iterator, bool> std::set<_Key, _Compare, _Alloc>::insert(const _Key&) [with _Key = IObserver, _Compare = std::less<IObserver>, _Alloc = std::allocator<IObserver>]’
prog.cpp:25:   instantiated from here
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_function.h:230: error: no match for ‘operator<’ in ‘__x < __y’

Обратите внимание, что я делаю большую часть своего программирования на C #, так что извините за мое невежество, когда дело доходит до "нюансов" C ++. Может кто-нибудь помочь мне понять, как правильно это осуществить?

Обновление

Изменил мой код на основе ответа Наваза, вот обновленный код: http://www.ideone.com/AH3KG

Ответы [ 3 ]

2 голосов
/ 27 июля 2011

Единственное, что вы не сможете легко исправить, просто прочитав сообщения об ошибках:

std::set<IObserver> observers;

Это должен быть набор указателей.Делать копии объектов-наблюдателей почти наверняка неправильно.Используйте

std::set<IObserver*> observers;

Это также исправит проблему с less_than, поскольку указатели можно сравнивать, даже если объекты, на которые они указывают, не определяют порядок.

Вот оно,исправлено: http://ideone.com/9jzpK

Так как вы упомянули о корректности констант, вот вариант, в котором наблюдатели const: http://ideone.com/gxsCo

2 голосов
/ 27 июля 2011

Причина в том, что все объекты в set являются неизменяемыми, поэтому вы не можете вызвать для них мутантную функцию (CallMeBack).

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

Если вы сделаете набор, содержащий (умные в зависимости от владельца) указатели, это решит обе проблемы одновременно.

1 голос
/ 27 июля 2011
itr->("x","y",z);

Что это? Вы хотели написать это:

itr->CallMeBack("x","y",z);

Во-вторых, сделайте B(const A& a) как:

 B(A& a);

То есть параметр не должен быть постоянным. И другие ошибки слишком легко распознать, например, вы используете a в деструкторе B, но это не переменная-член класса. Приложите усилия для чтения сообщений об ошибках и исправьте их самостоятельно.

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