当前位置: 首页 > 编程笔记 >

C++中如何实现回调的方法示例

吕征
2023-03-14
本文向大家介绍C++中如何实现回调的方法示例,包括了C++中如何实现回调的方法示例的使用技巧和注意事项,需要的朋友参考一下

前言

C++中使用class语法实现回调(当然,,旧式的C函数指针回调也是支持的)

比如,有人提供一个类库 AfCopyFile,能够提供文件拷贝的功能,而且能通知用户当前的进度。。。

int DoCopy(const char* source,
const char* dst,
AfCopyFileListener* listener);

用户只需要自己实现一个AfCopyFileListener对象,传给这个函数就行。。。

class MainJob : public AfCopyFileListener{
int OnCopyProgress(long long total,
long long transfered){
 }
}

把Listener对象传过去

AfCopyFile af;
af.DoCopy(source, dst, this); 

回调机制的缺点:

无论是C语言的回调函数,还是C++里的Listener,都有一个共同的缺点:

它使代码逻辑变得难以阅读。。

我们应尽量避免使用回调机制,最好采用单向的函数调用。

示例代码:

AfCopyFile.h

#ifndef _AF_COPY_FILE_H
#define _AF_COPY_FILE_H

class AfCopyFile
{
public:
 // 作为内部类
 class Listener
 {
 public:
  virtual int OnCopyProgress(long long total, long long transfered) = 0;
 };

public:
 int DoCopy(const char* source, const char* dst, Listener* listener);

};

#endif

AfCopyFile.cpp

#include <stdio.h>
#include <Windows.h>

#include "AfCopyFile.h"


// 将LARGE_INTTEGER类型转成unsigned long long
inline unsigned long long translate(LARGE_INTEGER num)
{
 unsigned long long result = num.HighPart;
 result <<= 32;
 result += num.LowPart;
 return result;
}

// 回调函数
// 注:要求将此函数用关键字CALLBACK修饰(这是Windows API的要求)
static DWORD CALLBACK CopyProgress( 
       LARGE_INTEGER TotalFileSize,
       LARGE_INTEGER TotalBytesTransferred,
       LARGE_INTEGER StreamSize,
       LARGE_INTEGER StreamBytesTransferred,
       DWORD dwStreamNumber,
       DWORD dwCallbackReason,
       HANDLE hSourceFile,
       HANDLE hDestinationFile,
       LPVOID lpData) // <- 这个就是上下文件对象
{
 // 计算百分比
 unsigned long long total = translate(TotalFileSize);
 unsigned long long copied = translate(TotalBytesTransferred);

 // 打印进度
 AfCopyFile::Listener* listener = (AfCopyFile::Listener*) lpData;
 listener->OnCopyProgress(total, copied);

 return PROGRESS_CONTINUE;
}

int AfCopyFile::DoCopy(const char* source, const char* dst, Listener* listener)
{
 BOOL ret = CopyFileEx(source, dst,
  &CopyProgress, // 待回调的函数
  listener,  // 上下文对象
  NULL, 0);
 
 return ret ? 0 : -1;
}

main.cpp

#include <stdio.h>
#include <string.h>
#include "AfCopyFile.h"

class MainJob : public AfCopyFile::Listener
{
public:
 int DoJob()
 {
  strcpy(user, "shaofa");
  strcpy(source, "c:\\test\\2.rmvb" );
  strcpy(dst, "c:\\test\\2_copy.rmvb");

  AfCopyFile af;
  af.DoCopy(source, dst, this); // 将this传过去
 
  return 0;
 }

 int OnCopyProgress(long long total, long long transfered)
 {
  // 打印进度
  int percent = (int) ( (transfered * 100 / total) );  
  printf("[用户: %s], %s -> %s : 进度 %d %%\n", 
   user, source, dst, percent);

  return 0;
 }

private:
 char source[256];
 char dst[256];
 char user[64];
};

int main()
{
 MainJob job;
 job.DoJob();

 return 0;
}

总结

以上就是这篇文章的全部内容,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对小牛知识库的支持。

 类似资料:
  • 本文向大家介绍C++调用C#的DLL实现方法,包括了C++调用C#的DLL实现方法的使用技巧和注意事项,需要的朋友参考一下 SwfDotNet是C#编写的,这是个特别好的读写Swf文件的库。本文讲述了在C++项目中,怎么让C++调用C#的DLL动态链接库文件。 具体的实现步骤如下: 一、创建C# DLL,需要指定应用类型为“类库”,代码: 二、C++客户程序,是个控制台应用,代码: 三、这里有几点

  • 本文向大家介绍ASP.NET中如何实现回调,包括了ASP.NET中如何实现回调的使用技巧和注意事项,需要的朋友参考一下 一、引言 在ASp.NET网页的默认模型中,用户通过单击按钮或其他操作的方式来提交页面,此时客户端将当前页面表单中的所有数据(包括一些自动生成的隐藏域)都提交到服务器端,服务器将重新实例化一个当前页面类的实例来响应这个请求,然后将整个页面的内容重新发送到客户端。这种处理方式对运行

  • 本文向大家介绍C#中调用VB中Inputbox类的实现方法,包括了C#中调用VB中Inputbox类的实现方法的使用技巧和注意事项,需要的朋友参考一下 C#自己没有Inputbox这个类,但是Inputbox也蛮好用的,所以有两种方法可以使用 一:间接调用vb中的Inputbox功能       1。在项目中添加对Microsoft.VisualBasic引用       2。在项目中添加命名空间

  • 问题内容: 回调如何用PHP编写? 问题答案: 该手册可互换地使用术语“回调”和“可调用”,但是,“回调”传统上是指充当函数指针的字符串或数组值,并引用函数或类方法以供将来调用。自PHP 4以来,已经允许使用函数式编程的某些元素。 通常,这是使用可调用值的安全方法: 现代PHP版本允许上面的前三种格式直接作为调用。并支持以上所有内容。 注释/注意事项: 如果函数/类已命名空间,则字符串必须包含标准

  • 问题内容: 我正在尝试从C 调用python类中的方法。调用它的C 方法是C ++回调。 在此方法中,当我尝试调用python方法时,它给出了。 我已经将python函数的实例保存在全局变量中,例如 python方法在哪里,将在回调中使用。 在回调中,参数创建为 创建时 在这一行中,它给出了细分错误。之后,实际的python方法称为 问题答案: 如果要从C / C ++回调中调用Python函数,

  • 本文向大家介绍C#中子类调用父类的实现方法,包括了C#中子类调用父类的实现方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了C#中实现子类调用父类的方法,分享给大家供大家参考之用。具体方法如下: 一、通过子类无参构造函数创建子类实例 创建父类Person和子类Student。 在客户端通过子类无参构造函数创建子类实例。 输出结果: 可见:通过调用子类无参构造函数创建子类实例,会默认调用父