Implement events (Delegation) in C ++)

Source: Internet
Author: User

Three methods for implementing callback (C-style callback functions, Sink method and Delegate method ). In object-oriented development, the delegate method is the most flexible and convenient, so someone has long used complicated templates to simulate it (if you are interested, refer to here and here ), in short, implementation is complicated. However, with the help of C ++ 11 functions and bind, we can easily implement it. Below is my own implementation method: namespace Common {typedef void * cookie_type; template <typename TR, typename T1, typename T2> class CEvent {public: typedef TR return_type; typedef T1 first_type; typedef T2 second_type; typedef std: function <return_type (first_type, second_type)> handler_type ;~ CEvent () {Clear ();} return_type operator () (first_type p1, second_type p2) {return_type ret = return_type (); size_t size = _ handlers. size (); for (size_t I = 0; I <size; ++ I) {ret = _ handlers [I]-> operator () (p1, p2 );} return ret;} cookie_type AddHandler (std: function <return_type (first_type, second_type)> h) {CEventHandler * p = new (nothrow) CEventHandler (h); if (p! = Nullptr) _ handlers. push_back (p); return (cookie_type) p;} template <typename class_type, typename class_fun> cookie_type AddHandler (class_type * pThis, class_fun f) {CEventHandler * p = new (nothrow) CEventHandler (pThis, f); if (p! = Nullptr) _ handlers. push_back (p); return (cookie_type) p;} void RemoveHandler (cookie_type cookie) {CEventHandler * p = (CEventHandler *) cookie; auto itr = std: find (_ handlers. begin (), _ handlers. end (), p); if (itr! = _ Handlers. end () {_ handlers. erase (itr); delete p;} else {assert (false) ;}} void Clear () {if (! _ Handlers. empty () {int n = _ handlers. size (); std: for_each (_ handlers. begin (), _ handlers. end (), [] (CEventHandler * p) {assert (p! = Nullptr); delete p;}); _ handlers. clear () ;}} private: class CEventHandler {public: CEventHandler (handler_type h) {_ handler = h; assert (_ handler! = Nullptr);} template <typename class_type, typename class_fun> classes (class_type * pThis, class_fun object_function) {using namespace std: placeholders; _ handler = std: bind (object_function, pThis, _ 1, _ 2); assert (_ handler! = Nullptr);} return_type operator () (first_type p1, second_type p2) {return_type ret = return_type (); assert (_ handler! = Nullptr); if (_ handler! = Nullptr) ret = _ handler (p1, p2); return ret;} handler_type _ handler;}; private: std: vector <CEventHandler *> _ handlers ;};} the general idea of implementation is that we encapsulate processing functions through a built-in CEventHandler class. We can add event processing functions through AddHandler, and a Cookie will be returned when adding them, we can use this Cookie to RemoveHandler. The following is the test code: # include "stdafx. h "# include <iostream> # include" event1.h "using namespace std; class CObjectX {}; class CClickEventArgs: public CObjectX {}; class CButton: Public CObjectX {public: void FireClick () {CClickEventArgs args; OnClicked (this, args);} Common: CEvent <int, CObjectX *, CClickEventArgs &> OnClicked ;}; class CMyClass {public: int OnBtuttonClicked (CObjectX * pButton, CClickEventArgs & args) {cout <"CMyClass: Receive button clicked event" <endl; return 1 ;}}; int OnBtuttonClicked_C_fun (CObjectX * pButton, CClickEventArgs & args) {cout <"C Style Function: Receive button clicked event "<endl; return 1;} class CMyFunObj {public: int operator () (CObjectX * pButton, CClickEventArgs & args) {cout <" Functor: receive button clicked event "<endl; return 1 ;}; int _ tmain (int argc, _ TCHAR * argv []) {using namespace std: placeholders; CButton btn; CMyClass obj; Common: cookie_type c1 = btn. onClicked. addHandler (& obj, & CMyClass: OnBtuttonClicked ); Common: cookie_type c2 = btn. onClicked. addHandler (OnBtuttonClicked_C_fun); CMyFunObj functor; Common: cookie_type c3 = btn. onClicked. addHandler (functor); btn. fireClick (); btn. onClicked. removeHandler (c2); std: cout <endl; btn. fireClick (); system ("pause"); return 0;} The following is the test result: we can see that in normal C Functions, class member functions and function imitation (functor) all tests passed. In addition, if the return value of the event function is void, a compilation error occurs. We need to make it special: template <typename T1, typename T2> class CEvent <void, T1, T2> {public: typedef void return_type; typedef T1 first_type; typedef T2 second_type; typedef std: function <return_type (first_type, second_type)> handler_type ;~ CEvent () {Clear ();} return_type operator () (first_type p1, second_type p2) {size_t size = _ handlers. size (); for (size_t I = 0; I <size; ++ I) {_ handlers [I]-> operator () (p1, p2 );}} cookie_type AddHandler (std: function <return_type (first_type, second_type)> h) {CEventHandler * p = new (nothrow) CEventHandler (h); if (p! = Nullptr) _ handlers. push_back (p); return (cookie_type) p;} template <typename class_type, typename class_fun> cookie_type AddHandler (class_type * pThis, class_fun f) {CEventHandler * p = new (nothrow) CEventHandler (pThis, f); if (p! = Nullptr) _ handlers. push_back (p); return (cookie_type) p;} void RemoveHandler (cookie_type cookie) {CEventHandler * p = (CEventHandler *) cookie; auto itr = std: find (_ handlers. begin (), _ handlers. end (), p); if (itr! = _ Handlers. end () {_ handlers. erase (itr); delete p;} else {assert (false) ;}} void Clear () {if (! _ Handlers. empty () {int n = _ handlers. size (); std: for_each (_ handlers. begin (), _ handlers. end (), [] (CEventHandler * p) {assert (p! = Nullptr); delete p;}); _ handlers. clear () ;}} private: class CEventHandler {public: CEventHandler (handler_type h) {_ handler = h; assert (_ handler! = Nullptr);} template <typename class_type, typename class_fun> classes (class_type * pThis, class_fun object_function) {using namespace std: placeholders; _ handler = std: bind (object_function, pThis, _ 1, _ 2); assert (_ handler! = Nullptr);} return_type operator () (first_type p1, second_type p2) {assert (_ handler! = Nullptr); if (_ handler! = Nullptr) _ handler (p1, p2);} handler_type _ handler;}; private: std: vector <CEventHandler *> _ handlers ;}; finally, let's talk about the problems encountered in writing this Code: (1) if you don't know if you can find the following code problems, I planted them here when writing the Code: vector <int *> v; int * p1 = new int (1); v. push_back (p1); int * p2 = new int (2); v. push_back (p2); // try to delete all items whose values are p1 // think of => v. erase (std: remove (v. begin (), v. end (), p1), v. end (); auto itr = remove (v. begin (), v. end (), p1); for_each (itr, v. end (), [] (Int * p) {delete p;}); v. erase (itr, v. end (); (2) We want to put cookei_type in the class, like this: 1 template <typename TR, typename T1, typename T2> 2 class CEvent3 {4 public: 5 typedef TR return_type; 6 typedef T1 first_type; 7 typedef T2 second_type; 8 typedef void * cookie_type; can be found to use: Common: CEvent <int, CObjectX *, CClickEventArgs & >:: cookie_type c1 = btn. onClicked. addHandler (& obj, & CMyClass: OnBtuttonClicked); too inconvenient, no Do you have any good solutions.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.