尝试实现观察者模式时出现多个编译器错误
Multiple compiler errors while trying to implement the observer pattern
我之前发布了一个关于如何将成员函数强制转换为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
,但它不是类的成员变量。在阅读错误消息时要付出一些努力,并自己修复这些错误。
- MSVC多行宏编译器错误
- 静态数据成员的问题-修复链接错误会导致编译器错误
- C++,我收到一个无法理解的编译器错误
- 我收到同义重复编译器错误。我应该如何修复"类型"X"的参数与类型"X"的参数不兼容?
- 重载方法的方式会在使用临时调用时生成编译器错误
- 尝试使用继承和模板实现CRTP.Visual Studio正在生成编译器错误
- 编译器错误:destuctor 的更宽松的抛出说明符
- Android NDK clang 编译器错误在 Windows 上显示'No such file or directory'
- C++ G++ 编译器 - 错误:隐式声明的定义
- 这个失败的测试是将零添加到空指针未定义的行为、编译器错误还是其他什么?
- 模板模板参数和模板别名:编译器错误?
- C++ 编译器错误:P1LinkedList.cpp:145:错误:重载的"to_string(int&)"调用不明确
- 在gcc中意外调用了Const重载.编译器错误或兼容性修复程序
- C1001内部编译器错误是由于矢量初始化(如数组)引起的
- 编译器错误(英特尔并行工作室 2019 与 Visual Studio 社区 2019)
- 如何在C++中克服此 C4430 编译器错误?
- 尝试使用 WinBGI 显示文本时出现编译器错误
- 使用typedef'ed返回类型声明友元函数时出现编译器错误
- 如何在类模板的成员函数中正确调用函数对象?正在生成 Visual Studio 编译器错误 C2440
- C++自定义分配器大小参数作为模板参数会引发编译器错误