2016-06-22 107 views
0

我来自C#世界,所以事件和事件处理程序是日常的东西。 最近我一直在研究wxWidgets 我一直在搜索这个问题已经有一个星期了,我发现大多数C++程序员很难理解术语“事件”或“回调”,也许它在C++世界中是模棱两可的。C++成员函数指针或事件驱动编程

下面是事件模型的一个简单示例。

class A{ 
public: 
    A(){ 
     child.MySuperClickEvent = this.HandleSuperClick; 
    } 
private: 
    B child; 

    void HandleSuperClick(B child){ 
     // do stuff 
    } 
} 


class B{ 
public: 
    /*TBA*/ MySuperClickEvent; 
private: 
    void ClickPrivate(){ 
     MySuperClickEvent(this); 
    } 
} 

B类有它自己的指定目的,当它完成时触发一个事件。 这个想法是,B类不应该有任何关于它的领域的知识,使它更可重用。

我已阅读关于std :: function <>和函数指针。所有这些似乎都在处理静态功能方面举了一些例子,但只要“会员对会员”的言论开始变得油腻起来。

总之,问题很简单。我如何制作一个可以从外部分配给成员的成员函数指针?

+0

什么是“小孩”? – immibis

+0

更新了问题。这有意义吗? – CyberFox

回答

0

有很多种方法可以实现这些功能,这些方法在内存开销,支持多少回调,线程安全性, weak_ptr s到看是否存在参与仍然对象等。

就像一个味道,让你开始 - 这里有一个简单的单线程“观察员”的实施做基本上你的问题问什么:

#include <iostream> 
#include <list> 

struct Observer 
{ 
    virtual ~Observer() { } 
    virtual void on_event_x() { } 
}; 

class Observable 
{ 
    public: 
    void add_observer(Observer& o) 
    { 
     observers_.push_back(&o); 
    } 

    void do_some_stuff() 
    { 
     std::cout << "before 1st event\n"; 
     fire_event_x(); 
     std::cout << "between 1st & 2nd events\n"; 
     fire_event_x(); 
     std::cout << "after 2nd event\n"; 
    } 

    private: 
    std::list<Observer*> observers_; 

    void fire_event_x() 
    { 
     for (auto& observer : observers_) 
      observer->on_event_x(); 
    } 
}; 

struct My_Observer : Observer 
{ 
    My_Observer(int id) : id_(id) { } 

    void on_event_x() override 
    { 
     std::cout << "My_Observer::on_event_x() id " << id_ << '\n'; 
    } 

    int id_; 
}; 

int main() 
{ 
    My_Observer my_observer_1 { 1 }; 
    My_Observer my_observer_2 { 2 }; 
    Observable x; 
    x.add_observer(my_observer_1); 
    x.add_observer(my_observer_2); 
    x.do_some_stuff(); 
} 

运行时输出:

before 1st event 
My_Observer::on_event_x() id 1 
My_Observer::on_event_x() id 2 
between 1st & 2nd events 
My_Observer::on_event_x() id 1 
My_Observer::on_event_x() id 2 
after 2nd event 

如果不适合你功能,请准确说出为什么。

+0

谢谢你的时间。 “观察者”这个词对我来说很陌生。但是阅读代码:它看起来像是一种事件实现。但据我所见,你没有附加任何回调/函数到这个“观察者”,而是你继承和重写“on_event_x”函数。我会用这个解决方案修改一下 – CyberFox

+0

@Cyber​​Fox:不客气。 [Observer](qt_config)是经典设计模式之一,值得学习 - 如果您有时间和兴趣,“四人帮”一书[设计模式](https://en.wikipedia.org/wiki/Design_Patterns)会给你一个很好的,温柔的介绍,以及其他非常常见的模式。正如你所说,我选择说明的实现使用虚拟分发(C++的运行时多态的机制)而不是显式函数指针或'std :: function <>'实例,但所有这些都是选项 - 后者是最灵活的,但后者是可选的'remove_observer()'变得更加棘手。 –

+0

我已经尝试了大约一周的解决方案。我在模板中混合来制作一个通用的解决方案。但是,当模板和继承被组合为特定级别时,C++停止了类型推理或类似的事情。像迭代器无法找到循环变量。我不确定这是C++编译器中的一个小故障还是我无能为力。 (prolly后者) – CyberFox

0

由于这个问题被标记wxWidgets,让我回答了它的更窄的变体,即如何使用成员函数作为wxWidgets的事件处理程序:

这与Bind()方法的帮助下可以用做直接使用成员函数(您将指针传递给函数本身并将对象传递给它)或任何函数,即可以使用标准函数调用语法调用的任何函数,例如std::function<>对象,可以用来存储任何可调用的对象。

+0

该文档几乎不提供足够的信息,它们链接的事件示例是GitHub上的~600行文件。你能提供一个简单的例子吗? – CyberFox

+0

对于你感兴趣的功能,你甚至应该能够对6000行样本进行扫描,但是让我[做这个](https://github.com/wxWidgets/wxWidgets/blob/v3.1.0/samples/)事件/ event.cpp#L514)。 –

+0

我可能可以导航6000行C#代码。所以是的,我真的应该得到那匹马。我也在“Bind”上找到了带有ctrl + f的第514行。但我仍然有点迷路。 wxEVT_BUTTON全局常量。这只是一个数字。文档中提到了EventType,但这真的意味着什么?如果我定义了一个不同的常量,它会附加到不同的事件。或者我放在那里没有关系? – CyberFox