C++中回调的实现
2017-10-04 本文已影响79人
NiceBlueChai
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;
}
❤️我的目标是:someday,即便你花钱看我的文章,也会觉得心满意足