开源时代C语言程序员

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,即便你花钱看我的文章,也会觉得心满意足


上一篇下一篇

猜你喜欢

热点阅读