c++回调函数 callback

2024-05-31 05:08
文章标签 c++ 函数 回调 callback

本文主要是介绍c++回调函数 callback,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1Callback方式
Callback
的本质是设置一个函数指针进去,然后在需要需要触发某个事件时调用该方法比如Windows的窗口消息处理函数就是这种类型。比如下面的示例代码,我们在Download完成时需要触发一个通知外面的事件:

  

复制代码
 1 typedef void (__stdcall *DownloadCallback)(const char* pURL, bool bOK);  
 2 void DownloadFile(const char* pURL, DownloadCallback callback)  
 3 {  
 4     cout << "downloading: " << pURL << "" << endl;  
 5     callback(pURL, true);  
 6 }  
 7 void __stdcall OnDownloadFinished(const char* pURL, bool bOK)  
 8 {  
 9     cout << "OnDownloadFinished, URL:" << pURL << "    status:" << bOK << endl;  
10 } 
复制代码

 

(2)Sink方式

Sink的本质是你按照对方要求实现一个C++接口,然后把你实现的接口设置给对方,对方需要触发事件时调用该接口, COM中连接点就是居于这种方式。上面下载文件的需求,如果用Sink实现,代码如下:

 

 

复制代码
 1 class IDownloadSink  
 2 {  
 3 public:  
 4     virtual void OnDownloadFinished(const char* pURL, bool bOK) = 0;  
 5 };  
 6     
 7     
 8 class CMyDownloader  
 9 {  
10 public:  
11     CMyDownloader(IDownloadSink* pSink)  
12         :m_pSink(pSink)  
13     {  
14     }  
15     
16     void DownloadFile(const char* pURL)  
17     {  
18         cout << "downloading: " << pURL << "" << endl;  
19         if(m_pSink != NULL)  
20         {  
21             m_pSink->OnDownloadFinished(pURL, true);  
22         }  
23     }  
24     
25 private:  
26     IDownloadSink* m_pSink;  
27 };  
28     
29 class CMyFile: public IDownloadSink  
30 {  
31 public:  
32     void download()  
33     {  
34         CMyDownloader downloader(this);  
35         downloader.DownloadFile("www.baidu.com");  
36     }  
37     
38     virtual void OnDownloadFinished(const char* pURL, bool bOK)  
39     {  
40         cout << "OnDownloadFinished, URL:" << pURL << "    status:" << bOK << endl;  
41     }  
42 };  
复制代码

 

 

 

(3)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);  
}  class CDownloadEvent  
{  
public:  ~CDownloadEvent()  {  vector<CDownloadDelegateBase*>::iterator itr = m_arDelegates.begin();  while (itr != m_arDelegates.end())  {  delete *itr;  ++itr;  }  m_arDelegates.clear();  }  void operator += (CDownloadDelegateBase* p)  {  m_arDelegates.push_back(p);  }  void operator -= (CDownloadDelegateBase* p)  {  ITR itr = remove(m_arDelegates.begin(), m_arDelegates.end(), p);  ITR itrTemp = itr;  while (itrTemp != m_arDelegates.end())  {  delete *itr;  ++itr;  }  m_arDelegates.erase(itr, m_arDelegates.end());  }  void operator()(const char* pURL, bool bOK)  {  ITR itrTemp = m_arDelegates.begin();  while (itrTemp != m_arDelegates.end())  {  (*itrTemp)->Fire(pURL, bOK);  ++itrTemp;  }  }  private:  vector<CDownloadDelegateBase*> m_arDelegates;  typedef vector<CDownloadDelegateBase*>::iterator ITR;  
};  class CMyDownloaderEx  
{  
public:  void DownloadFile(const char* pURL)  {  cout << "downloading: " << pURL << "" << endl;  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)  {  cout << "OnDownloadFinished, URL:" << pURL << "    status:" << bOK << endl;  }  
}; 
复制代码

 

 

    可以看到Delegate的方式代码量比上面其他2种方式大多了,并且我们上面是固定参数数量和类型的实现方式,如果要实现可变参数,要更加麻烦的多。可变参数的方式可以参考这2种实现:

Yet Another C#-style Delegate Class in Standard C++
Member Function Pointers and the Fastest Possible C++ Delegates

   

我们可以用下面的代码测试我们上面的实现:

 

 

 

复制代码
int _tmain(int argc, _TCHAR* argv[])  
{  DownloadFile("www.baidu.com", OnDownloadFinished);  CMyFile f1;  f1.download();  CMyFileEx ff;  ff.download();  system("pause");  return 0;  
}  
复制代码

 

 

最后简单比较下上面3种实现回调的方法:


第一种Callback的方法是面向过程的,使用简单而且灵活,正如C语言本身。
第二种Sink的方法是面向对象的,在C++里使用较多,可以在一个Sink里封装一组回调接口,适用于一系列比较固定的回调事件。
第三种Delegate的方法也是面向对象的,和Sink封装一组接口不同,Delegate的封装是以函数为单位,粒度比Sink更小更灵活。

你更倾向于用哪种方式来实现回调?

 

还有一种是通过sigslot信号槽机制来实现委托

 相关sigslot的用法可以参考这篇文章。

相关头文件下载地址

这篇关于c++回调函数 callback的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1017417

相关文章

C++中unordered_set哈希集合的实现

《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder... 目录一、概述二、头文件与命名空间三、常用方法与示例1. 构造与析构2. 迭代器与遍历3. 容量相关4

C++中悬垂引用(Dangling Reference) 的实现

《C++中悬垂引用(DanglingReference)的实现》C++中的悬垂引用指引用绑定的对象被销毁后引用仍存在的情况,会导致访问无效内存,下面就来详细的介绍一下产生的原因以及如何避免,感兴趣... 目录悬垂引用的产生原因1. 引用绑定到局部变量,变量超出作用域后销毁2. 引用绑定到动态分配的对象,对象

Python函数作用域与闭包举例深度解析

《Python函数作用域与闭包举例深度解析》Python函数的作用域规则和闭包是编程中的关键概念,它们决定了变量的访问和生命周期,:本文主要介绍Python函数作用域与闭包的相关资料,文中通过代码... 目录1. 基础作用域访问示例1:访问全局变量示例2:访问外层函数变量2. 闭包基础示例3:简单闭包示例4

Python中isinstance()函数原理解释及详细用法示例

《Python中isinstance()函数原理解释及详细用法示例》isinstance()是Python内置的一个非常有用的函数,用于检查一个对象是否属于指定的类型或类型元组中的某一个类型,它是Py... 目录python中isinstance()函数原理解释及详细用法指南一、isinstance()函数

python中的高阶函数示例详解

《python中的高阶函数示例详解》在Python中,高阶函数是指接受函数作为参数或返回函数作为结果的函数,下面:本文主要介绍python中高阶函数的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录1.定义2.map函数3.filter函数4.reduce函数5.sorted函数6.自定义高阶函数

Python中的sort方法、sorted函数与lambda表达式及用法详解

《Python中的sort方法、sorted函数与lambda表达式及用法详解》文章对比了Python中list.sort()与sorted()函数的区别,指出sort()原地排序返回None,sor... 目录1. sort()方法1.1 sort()方法1.2 基本语法和参数A. reverse参数B.

C++读写word文档(.docx)DuckX库的使用详解

《C++读写word文档(.docx)DuckX库的使用详解》DuckX是C++库,用于创建/编辑.docx文件,支持读取文档、添加段落/片段、编辑表格,解决中文乱码需更改编码方案,进阶功能含文本替换... 目录一、基本用法1. 读取文档3. 添加段落4. 添加片段3. 编辑表格二、进阶用法1. 文本替换2

C++中处理文本数据char与string的终极对比指南

《C++中处理文本数据char与string的终极对比指南》在C++编程中char和string是两种用于处理字符数据的类型,但它们在使用方式和功能上有显著的不同,:本文主要介绍C++中处理文本数... 目录1. 基本定义与本质2. 内存管理3. 操作与功能4. 性能特点5. 使用场景6. 相互转换核心区别

Python函数的基本用法、返回值特性、全局变量修改及异常处理技巧

《Python函数的基本用法、返回值特性、全局变量修改及异常处理技巧》本文将通过实际代码示例,深入讲解Python函数的基本用法、返回值特性、全局变量修改以及异常处理技巧,感兴趣的朋友跟随小编一起看看... 目录一、python函数定义与调用1.1 基本函数定义1.2 函数调用二、函数返回值详解2.1 有返

Python Excel 通用筛选函数的实现

《PythonExcel通用筛选函数的实现》本文主要介绍了PythonExcel通用筛选函数的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着... 目录案例目的示例数据假定数据来源是字典优化:通用CSV数据处理函数使用说明使用示例注意事项案例目的第一