尝试实现观察者模式时出现多个编译器错误

Multiple compiler errors while trying to implement the observer pattern

本文关键字:编译器 错误 实现 观察者模式      更新时间:2023-10-16

我之前发布了一个关于如何将成员函数强制转换为typedef函数指针的问题(如何使用typedef功能指针注册回调(,它促使我考虑通过实现"经典"观察者模式来稍微修改一下解决方案。

我想允许类A通知通过函数指针获得回调的观察者和通过成员函数获得回调的观察员,但我不知道什么是最正确的方法。我在网上看了其他的例子,现在我很困惑自己哪里错了。

以下是我粘贴在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正确性,因此这里有一个变体,其中的观察者是const:http://ideone.com/gxsCo

原因是set中的所有对象都是不可变的,因此不能对它们调用可变函数(CallMeBack(。

此外,由于您在集合中按值存储观察者,因此它们将被切片,并且永远不会表现出任何多态行为。

如果您使集合包含(智能取决于所有权(指针,则可以同时解决这两个问题。

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

这是什么?你想写这个:

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

第二,使B(const A& a)为:

 B(A& a);

也就是说,参数不应该是const。其他错误太容易识别,例如,在B的析构函数中使用a,但它不是类的成员变量。在阅读错误消息时要付出一些努力,并自己修复这些错误。