当覆盖存在时调用基本虚拟"binded to object"函数



我希望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一起使用,因为几个类继承了 ftomObserver.
输出:
virtual void Observer::onNewGame()
但我希望:
virtual void Npc::onNewGame()

首先,不要使用std::bind()。它几乎已经过时了。(更喜欢 lambda。

其次,如果你直接调用它而不是std::bind(),它将起作用:

(observer.*eventMethod)();

Coliru上直播,其中输出是所需的:

virtual void Npc::onNewGame()

或者,如果您有 C++17 支持,则可以使用std::invoke(),根据此C++有关间接调用成员函数的常见问题解答。

您可以考虑使用像 Boost.Signals2 这样的高质量观察器库,而不是自己创建。如果您确实需要自己动手,请考虑使用std::function作为其基础。

PS、风格提示:

  1. 您不需要散布在整个代码中的所有this->。也许它们来自需要它们的更复杂的上下文,但正如所写,它们是多余的。
  2. 最好将非基类中的virtual替换为override,以帮助编译器帮助您避免错误。
  3. 通过向不修改成员数据的函数(如NotifiernotifyNewGame()notifyAll()(添加const来首选const正确性。
std::bind

不存储对对象的引用,因此您可以获得它的一部分.
立即的解决方法是再次使用std::ref

std::bind(eventMethod, std::ref(observer))()

但是bind是不必要的间接寻址,您可以更直接地完成相同的操作:

(observer.*eventMethod)()

或使用std::function

void notifyNewGame() {
notifyAll([](Observer& o) { o.onNewGame(); } );
}
void notifyAll(std::function<void(Observer&)> fn) {
std::for_each(observers.begin(), observers.end(), fn); 
}

最新更新