尝试实现观察者模式时出现多个编译器错误
我之前发布了一个关于如何将成员函数转换为 typedef 函数指针的问题( 如何使用 typedef 函数指针来注册回调),它促使我考虑通过实现“经典”观察者模式来稍微修改一下解决方案。
我想允许类 A
通知通过函数指针获取回调的观察者和通过成员函数获取回调的观察者,但我不知道什么是 const-正确的方法来做到这一点。我查看了其他在线示例,现在我'我只是对我哪里出错了感到困惑。
以下是我粘贴到 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
I posted a question earlier on how to cast a member function to a typedef function pointer ( How to use a typedef function pointer to register a callback ) and it prompted me to consider a slightly modified solution by implementing the "classic" observer pattern.
I want to allow class A
to notify observers who get a callback via the function pointer and observers who get a callback via a member function, but I can't figure out what's const-correct way to do this. I've looked at other examples online and now I'm just confused with where I'm going wrong.
Here is an sscce compliant example that I pasted in ideone.com (with the compiler errors below it):
#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;
}
};
Compiler Errors:
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’
Please note that I do most of my programming in C#, so excuse my ignorance when it comes to the "nuances" of C++. Could anybody help me figure out what's the right way to implement this?
Update
Changed my code based on Nawaz's answer, here is the updated code: http://www.ideone.com/AH3KG
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
仅通过阅读错误消息可能无法轻松修复的唯一问题是:
这需要是指针的集合。复制观察者对象几乎肯定是错误的做法。使用
此方法还可以解决
less_than
的问题,因为即使指针指向的对象没有定义顺序,也可以比较指针。在这里,已修复: http://ideone.com/9jzpK
既然您提到了 const-正确性,这里有一个变体其中观察者是
const
: http://ideone.com/gxsCoThe only thing that you might not be able to fix easily just by reading the error messages is:
This needs to be a collection of pointers. Making copies of the observer objects is almost certainly the wrong thing to do. Use
This will also fix the problem with
less_than
, because pointers can be compared even when the objects they point to don't define an ordering.Here it is, fixed: http://ideone.com/9jzpK
Since you mentioned const-correctness, here's a variant in which the observers are
const
: http://ideone.com/gxsCo原因是
set
中的所有对象都是不可变的,因此您无法对它们调用变异函数 (CallMeBack
)。此外,由于您在集合中按值存储观察者,因此它们将被切片并且永远不会表现出任何多态行为。
如果您使集合包含(智能取决于所有权)指针,则可以立即解决这两个问题。
The reason is that all objects in a
set
are immutable, so you can't call a mutating function (CallMeBack
) on them.Further, since you're storing the observers by value in your set they'll be sliced and never exhibit any polymorphic behavior.
If you make the set contain (smart depending on ownership) pointers, that solves both problems at once.
这是什么?你想这样写:
其次,将
B(const A& a)
设置为:也就是说,参数不应该是 const。还有一些错误太容易识别,例如,您在
B
的析构函数中使用了a
,但它不是该类的成员变量。努力阅读错误消息,并自行修复这些错误。What is this? You wanted to write this:
Second, make
B(const A& a)
as:That is, the parameter shouldn't be const. And other errors are too easy to recognize, for example, you're using
a
in the destructor ofB
, yet its not a member variable of the class. Make some effort in reading the error messages, and fix these error yourself.