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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > c/c++ >内容正文

c/c++

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

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


Callback

Callback的本質(zhì)是設(shè)置一個(gè)函數(shù)指針進(jìn)去,然后在需要觸發(fā)某個(gè)事件時(shí)調(diào)用該方法, 比如Windows的窗口消息處理函數(shù)就是這種類型。
比如下面的示例代碼,我們?cè)贒ownload完成時(shí)需要觸發(fā)一個(gè)通知外面的事件:

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的本質(zhì)是你按照對(duì)方要求實(shí)現(xiàn)一個(gè)C++接口,然后把你實(shí)現(xiàn)的接口設(shè)置給對(duì)方,對(duì)方需要觸發(fā)事件時(shí)調(diào)用該接口, COM中連接點(diǎn)就是居于這種方式。還是以上面的Download為例(你調(diào)用對(duì)方的下載類實(shí)現(xiàn)下載功能):

/*對(duì)方要求的接口*/ class IDownloadSink { public:virtual void OnDownloadFinished(const char* pURL, bool bOK) = 0; }; /*對(duì)方的實(shí)現(xiàn)*/ 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
/*你的實(shí)現(xiàn)*/ 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的本質(zhì)是設(shè)置成員函數(shù)指針給對(duì)方,然后讓對(duì)方在需要觸發(fā)事件時(shí)調(diào)用。C#中用Delegate的方式實(shí)現(xiàn)Event,讓C++程序員很是羨慕,C++中因?yàn)檎Z(yǔ)言本身的關(guān)系,要實(shí)現(xiàn)Delegate還是很麻煩的。上面的例子我們用Delegate的方式實(shí)現(xiàn)如下:

class CDownloadDelegateBase { public:virtual void Fire(const char* pURL, bool bOK) = 0; };/*模板類,實(shí)現(xiàn)代理函數(shù)的調(diào)用*/ 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; };/*模板函數(shù),創(chuàng)建代理*/ 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); }/*代理函數(shù)管理*/ 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; };/*應(yīng)用*/ class CMyFileEx { public:void download(){CMyDownloaderEx downloader;/*添加代理函數(shù)*/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種方式多多了,并且上面是固定參數(shù)數(shù)量和類型的實(shí)現(xiàn)方式,如果要實(shí)現(xiàn)可變參數(shù),要更加麻煩的多,具體可參考:
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是一個(gè)通用的多態(tài)函數(shù)包裝器。std :: function的實(shí)例可以存儲(chǔ),復(fù)制和調(diào)用任何可調(diào)用的目標(biāo):函數(shù)、lambda表達(dá)式、綁定表達(dá)式或其他函數(shù)對(duì)象。

#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

函數(shù)模板std :: mem_fn生成指向成員函數(shù)的指針的包裝對(duì)象,它可以存儲(chǔ),復(fù)制和調(diào)用指向成員函數(shù)的指針。 在調(diào)用std :: mem_fn時(shí),可以使用對(duì)象的引用和指針(包括智能指針)。

/* 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

小結(jié)

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

總結(jié)

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

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。