我之前发布了一个关于如何将成员函数强制转换为typedef函数指针(How to use a typedef function pointer to register a callback)的问题,这促使我通过实现“经典”观察者模式来考虑稍微修改过的解决方案。
我想允许类A
通过函数指针和通过成员函数获得回调的观察者通知通过回调获得回调的观察者,但我无法弄清楚这是什么常量的正确方法。我看了other examples online,现在我只是对我出错的地方感到困惑。
这是一个符合sscce的示例,我pasted in 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 ++“细微差别”的无知。有人可以帮我弄清楚实现这个的正确方法是什么?
根据Nawaz的回答更改了我的代码,以下是更新后的代码:http://www.ideone.com/AH3KG
答案 0 :(得分:2)
通过阅读错误消息,您可能无法轻松解决的唯一问题是:
std::set<IObserver> observers;
这需要是指针的集合。制作观察者对象的副本几乎肯定是错误的。使用
std::set<IObserver*> observers;
这也将解决less_than
的问题,因为即使指向的对象没有定义排序,也可以比较指针。
既然你提到了const-correctness,这里有一个观察者是const
的变体:http://ideone.com/gxsCo
答案 1 :(得分:2)
原因是set
中的所有对象都是不可变的,因此您无法在它们上调用变异函数(CallMeBack
)。
此外,由于您按照值在集合中存储观察者,因此它们将被切片并且从不表现出任何多态行为。
如果你设置包含(智能取决于所有权)指针,那么可以立即解决这两个问题。
答案 2 :(得分:1)
itr->("x","y",z);
这是什么?你想写这个:
itr->CallMeBack("x","y",z);
其次,将B(const A& a)
设为:
B(A& a);
也就是说,参数不应该是const。其他错误太容易识别,例如,你在a
的析构函数中使用B
,但它不是类的成员变量。努力阅读错误消息,并自己修复这些错误。