日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++回调机制的几种实现方式

發布時間:2023/12/18 c/c++ 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++回调机制的几种实现方式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.


Callback

Callback的本質是設置一個函數指針進去,然后在需要觸發某個事件時調用該方法, 比如Windows的窗口消息處理函數就是這種類型。
比如下面的示例代碼,我們在Download完成時需要觸發一個通知外面的事件:

typedef void (__stdcall *DownloadCallback)(const char* pURL, bool bOK); void DownloadFile(const char* pURL, DownloadCallback pCallback) {……pCallback (pURL, true); } void __stdcall OnDownloadFinished(const char* pURL, bool bOK) {…… }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Sink

Sink的本質是你按照對方要求實現一個C++接口,然后把你實現的接口設置給對方,對方需要觸發事件時調用該接口, COM中連接點就是居于這種方式。還是以上面的Download為例(你調用對方的下載類實現下載功能):

/*對方要求的接口*/ class IDownloadSink { public:virtual void OnDownloadFinished(const char* pURL, bool bOK) = 0; }; /*對方的實現*/ class CMyDownloader { public:CMyDownloader(IDownloadSink* pSink) : m_pSink(pSink) { }void DownloadFile(const char* pURL){……if(m_pSink != NULL)m_pSink->OnDownloadFinished(pURL, true);}private:IDownloadSink* m_pSink; };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
/*你的實現*/ class CMyFile: public IDownloadSink { public:void Download(){CMyDownloader downloader(this);downloader.DownloadFile("www.baidu.com");}virtual void OnDownloadFinished(const char* pURL, bool bOK){……} }
  • 15

Delegate

Delegate的本質是設置成員函數指針給對方,然后讓對方在需要觸發事件時調用。C#中用Delegate的方式實現Event,讓C++程序員很是羨慕,C++中因為語言本身的關系,要實現Delegate還是很麻煩的。上面的例子我們用Delegate的方式實現如下:

class CDownloadDelegateBase { public:virtual void Fire(const char* pURL, bool bOK) = 0; };/*模板類,實現代理函數的調用*/ template<typename O, typename T> class CDownloadDelegate: public CDownloadDelegateBase {typedef void (T::*Fun)(const char*, bool); public:CDownloadDelegate(O* pObj = NULL, Fun pFun = NULL):m_pFun(pFun), m_pObj(pObj){ } virtual void Fire(const char* pURL, bool bOK){if(m_pFun != NULL && m_pObj != NULL){(m_pObj->*m_pFun)(pURL, bOK);}} private:Fun m_pFun;O* m_pObj; };/*模板函數,創建代理*/ template<typename O, typename T> CDownloadDelegate<O,T>* MakeDelegate(O* pObject, void (T::*pFun)(const char* pURL, bool)) {return new CDownloadDelegate<O, T>(pObject, pFun); }/*代理函數管理*/ typedef vector<CDownloadDelegateBase*> CDownloadDelegates; class CDownloadEvent { public:~CDownloadEvent(){CDownloadDelegates::iterator it = m_arDelegates.begin();while (it != m_arDelegates.end()){delete *it;++it;}m_arDelegates.clear();}void operator += (CDownloadDelegateBase* p){m_arDelegates.push_back(p);}void operator -= (CDownloadDelegateBase* p){CDownloadDelegates::iterator it = remove(m_arDelegates.begin(), m_arDelegates.end(), p);while (it != m_arDelegates.end()){delete *it;++it;}m_arDelegates.erase(it, m_arDelegates.end());}void operator()(const char* pURL, bool bOK){CDownloadDelegates::iterator it = m_arDelegates.begin();while (it != m_arDelegates.end()){(*it)->Fire(pURL, bOK);++it;}} private:CDownloadDelegates m_arDelegates; };class CMyDownloaderEx { public:void DownloadFile(const char* pURL){……downloadEvent(pURL, true);}CDownloadEvent downloadEvent; };/*應用*/ class CMyFileEx { public:void download(){CMyDownloaderEx downloader;/*添加代理函數*/downloader.downloadEvent += MakeDelegate(this, &CMyFileEx::OnDownloadFinished);downloader.DownloadFile("www.baidu.com");}virtual void OnDownloadFinished(const char* pURL, bool bOK){……} };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107

可以看到Delegate的方式代碼量比上面其他2種方式多多了,并且上面是固定參數數量和類型的實現方式,如果要實現可變參數,要更加麻煩的多,具體可參考:
http://www.codeproject.com/Articles/11464/Yet-Another-C-style-Delegate-Class-in-Standard-C
http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible

std::function(since C++ 11, vs2010)

template< class R, class... Args > class function<R(Args...)>
  • 1
  • 2
  • 1
  • 2

類模板std :: function是一個通用的多態函數包裝器。std :: function的實例可以存儲,復制和調用任何可調用的目標:函數、lambda表達式、綁定表達式或其他函數對象。

#include <functional> #include <iostream>struct Foo {Foo(int num) : num_(num) {}void print_add(int i) const { std::cout << num_+i << '\n'; }int num_; };void print_num(int i) {std::cout << i << '\n'; }int main() {// store a free functionstd::function<void(int)> f1 = print_num;f1(-9);// store a lambdastd::function<void()> f2 = []() { print_num(123); };f2();// store the result of a call to std::bindstd::function<void()> f3 = std::bind(print_num, 12345);f3();// store a call to a member functionstd::function<void(const Foo&, int)> f4 = &Foo::print_add;Foo foo(13579);f4(foo, 1); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

std::mem_fn (since C++ 11, vs2010)

template< class R, class T > /*unspecified*/ mem_fn(R T::* pm); template< class R, class T, class... Args > /*unspecified*/ mem_fn(R (T::* pm)(Args...)); template< class R, class T, class... Args > /*unspecified*/ mem_fn(R (T::* pm)(Args...) const); template< class R, class T, class... Args > /*unspecified*/ mem_fn(R (T::* pm)(Args...) volatile); template< class R, class T, class... Args > /*unspecified*/ mem_fn(R (T::* pm)(Args...) const volatile); template< class R, class T, class... Args > /*unspecified*/ mem_fn(R (T::* pm)(Args...) &); template< class R, class T, class... Args > /*unspecified*/ mem_fn(R (T::* pm)(Args...) const &); template< class R, class T, class... Args > /*unspecified*/ mem_fn(R (T::* pm)(Args...) volatile &); template< class R, class T, class... Args > /*unspecified*/ mem_fn(R (T::* pm)(Args...) const volatile &); template< class R, class T, class... Args > /*unspecified*/ mem_fn(R (T::* pm)(Args...) &&); template< class R, class T, class... Args > /*unspecified*/ mem_fn(R (T::* pm)(Args...) const &&); template< class R, class T, class... Args > /*unspecified*/ mem_fn(R (T::* pm)(Args...) volatile &&); template< class R, class T, class... Args > /*unspecified*/ mem_fn(R (T::* pm)(Args...) const volatile &&);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

函數模板std :: mem_fn生成指向成員函數的指針的包裝對象,它可以存儲,復制和調用指向成員函數的指針。 在調用std :: mem_fn時,可以使用對象的引用和指針(包括智能指針)。

/* Use mem_fn to store and execute a member function:*/ #include <functional> #include <iostream> struct Foo { void display_greeting() { std::cout << "Hello, world.\n"; } void display_number(int i) { std::cout << "number: " << i << '\n'; } }; int main() {Foo foo;auto func_greet = std::mem_fn(&Foo::display_greeting);func_greet(foo); auto func_display = std::mem_fn(&Foo::display_number);func_display(foo, 42); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
#include <iostream> #include <functional> #include <iterator> #include <memory> #include <string> #include <vector> #include <algorithm> int main() {/*Pass a member function to std::transform to create a sequence of numbers:*/std::vector<std::string> words = {"It", "is", "a", "test"};std::vector<std::unique_ptr<std::string>> words2; words2.emplace_back(new std::string("another")); words2.emplace_back(new std::string("test"));std::vector<std::size_t> lengths; std::transform(words.begin(), words.end(),std::back_inserter(lengths), std::mem_fn(&std::string::size)); // uses references to strings std::transform(words2.begin(), words2.end(), std::back_inserter(lengths),std::mem_fn(&std::string::size)); // uses unique_ptr to strings std::cout << "The string lengths are "; for(auto n : lengths) std::cout << n << ' '; std::cout << '\n'; }template<class InputIt, class OutputIt, class UnaryOperation> OutputIt transform(InputIt first1, InputIt last1, OutputIt d_first, UnaryOperation unary_op) {while (first1 != last1) {*d_first++ = unary_op(*first1++); } return d_first; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

小結

1) Callback方法是面向過程的,使用簡單而且靈活,正如C語言本身;
2) Sink方法是面向對象的,在C++里使用較多, 可以在一個Sink里封裝一組回調接口,適用于一系列比較固定的回調事件;
3) Delegate方法也是面向對象的,和Sink封裝一組接口不同,Delegate的封裝是以函數為單位,粒度比Sink更小更靈活;
4) std::function和std::bind組合使用也可以實現類似函數指針的功能,但卻卻比函數指針更加靈活,特別是函數指向類的非靜態成員函數時(本質上講全局函數和靜態成員函數沒有區別,使用方法上除了靜態成員函數在引用時要在前面加域作用符classname::外,沒有其它任何區別;事實上全局函數也有可能放入命名空間或者使用全局域作用符,例如 namespace::function() 或::function,這樣不僅本質上相同,形勢上也與靜態成員函數一致了)。在Effective C++中ITEM35建議使用該方法實現Strategy模式,實際上也可以用于代替callback 函數模仿C#中的event對象,而這里只能實現一個函數,實際上如果function<>模板實現了operator+以后,再在 function對象中維護一個列表,便可以實現C#中的event特性,即Delegate。

總結

以上是生活随笔為你收集整理的C++回调机制的几种实现方式的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。