我希望NotifyAll
将重写的子方法绑定到作为父引用存储的对象。 尽管继承,基方法仍然执行。 编译器似乎看不到重载,或者将向量元素视为非引用对象。 我在下面的代码中找不到我的坏处:
#include <iostream>
#include <functional>
#include <vector>
class Observer {
public:
virtual void onNewGame() {std::cout << __PRETTY_FUNCTION__ << '\n';}
};
class Npc: public Observer {
public:
virtual void onNewGame() {std::cout << __PRETTY_FUNCTION__ << '\n';}
};
class Notifier {
public:
void attach(Observer & observer) {
this->observers.push_back(std::ref(observer));
}
void notifyNewGame() {
this->notifyAll(&Observer::onNewGame);
}
void notifyAll(void(Observer::*eventMethod)(void)) {
for (Observer & observer : this->observers)
std::bind(eventMethod, observer)();
}
std::vector <std::reference_wrapper <Observer>> observers;
};
int main() {
Npc npc;
Notifier notifier;
notifier.attach(npc);
notifier.notifyNewGame();
}
我无法将std::bind
与&npc::OnNewGame
一起使用,因为有几个类继承了观察者
。
输出:Virtual void Observer::OnNewGame()
但我希望:Virtual void Npc::OnNewGame()
std::bind
不存储对该对象的引用,因此您将获得该对象的一部分。
立即的修复方法是再次使用std::ref
:
std::bind(eventMethod, std::ref(observer))()
但是绑定
是不必要的间接操作,您可以更直接地完成同样的操作:
(observer.*eventMethod)()
或者使用std::function
:
void notifyNewGame() {
this->notifyAll([](Observer& o) { o.onNewGame(); } );
}
void notifyAll(std::function<void(Observer&)> fn) {
std::for_each(observers.begin(), observers.end(), fn);
}
首先,不要使用std::bind()
。 它几乎已经过时了。 (优选lambdas.)
其次,如果您直接调用它或使用std::invoke()
而不是通过std::bind()
调用它,它将工作:
(observer.*eventMethod)();
在coliru上查看live,其中输出是所需的:
virtual void Npc::onNewGame()
另外,如果您支持C++17,则可以使用std::invoke()
间接调用成员函数。
您可以考虑使用像Boost.Signals2这样的高质量观察者库,而不是使用自己的观察者库。 如果确实需要滚动您自己的代码,请考虑使用std::function
作为其基础。
PS,风格提示:
this->
。 也许它们来自需要它们的更复杂的上下文,但正如所写的那样,它们是多余的。override
替换非基类中的virtual
,以帮助编译器帮助您避免错误。常量
-正确性,方法是将常量
添加到不修改成员数据的notifier
的NotifyNewGame()
和NotifyAll()
等函数。