我之前发布了一个问题,该问题关于如何将成员函数转换为typedef函数指针(How to use a typedef function pointer to register a callback),它促使我考虑通过实现“经典”观察者模式进行稍微修改的解决方案。

我想允许A类通知通过函数指针获得回调的观察者和通过成员函数获得回调的观察者,但是我无法弄清楚什么是const正确的方法。我看过other examples online,现在我只是对我要去的地方感到困惑。

这是我pasted in ideone.com的sscce兼容示例(下面有编译器错误):

#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++的“细微差别”。有人可以帮助我找出实现此方法的正确方法吗?

更新资料

根据Nawaz的答案更改了我的代码,这是更新的代码:http://www.ideone.com/AH3KG

最佳答案

仅通过阅读错误消息可能无法轻松修复的唯一事情是:

std::set<IObserver> observers;

这需要是指针的集合。几乎可以肯定,复制观察者对象是错误的事情。采用
std::set<IObserver*> observers;

这也将解决less_than的问题,因为即使指针指向的对象未定义顺序,也可以对其进行比较。

固定在这里:http://ideone.com/9jzpK

既然您提到了const-correctness,这是观察者使用const的一种变体:http://ideone.com/gxsCo

关于c++ - 尝试实现观察者模式时出现多个编译器错误,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/6848866/

10-12 17:28