函数指针与回调机制

来源:互联网 发布:网店美工教学大纲 编辑:程序博客网 时间:2024/06/06 07:35

1.函数指针
普通指针:修改内存的值;函数指针:调用函数
一个简单的实例:

#include<stdio.h>void print(int n){    printf("result:%d\n",n*n);}int main(){    void (* p)(int);    p=&print;//p=print;函数名就是指针地址    p(5);    getchar();    return 0;}

函数指针的使用:

    #include<stdio.h>void print(int n){    printf("result:%d\n",n*n);}typedef void (*my_Function)(int);//利用typedef为函数定义别名;防止可读性较差int main(){    my_Function p1=print;    p1(5);    getchar();    return 0;}

函数指针可以作为函数参数;

void test(my_Function p){    p(123);}

注:利用typedef可以增强函数的可读性;把函数指针变量同普通变量一样使用。
2.函数指针的回调机制
函数指针的应用场景:回调机制;
调用:调用第三方的类库(call)
回调:如果别人调用我们的函数叫回调(callback)
例子:拷贝文件

#include<stdio.h>#include <windows.h>//调用windows.api中的函数int main(){    const char *source="C:\\hao123.mp3";    const char *dst="D:\\hehe.mp3";    printf("start copy.......!\n");    bool result=CopyFile(source,dst,FALSE);    //从源文件中拷到目标文件中去。    printf("operation done:%s\n",result ? "success" : "failed");        return 0;}

缺点:文件较大时,缺少交互性。
增强交互性:及时通知应用程序
希望系统在工作时,时不时地调用我们的函数函数。
使用windows api的copyFileEx()函数;
我们将函数地址传给系统api函数;
具体实现:

#include <stdio.h>#include <Windows.h>// 将LARGE_INTTEGER类型转成unsigned long longunsigned long long translate(LARGE_INTEGER num){    unsigned long long result = num.HighPart;    result <<= 32;    result += num.LowPart;    return result;}// 回调函数// 注:要求将此函数用关键字CALLBACK修饰(这是Windows API的要求)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){    // 文件的总字节数 TotalFileSize    unsigned long long total = translate(TotalFileSize);    // 已经完成的字节数    unsigned long long copied =  translate(TotalBytesTransferred);    // 打印进度    printf("进度: %I64d / %I64d \n", copied, total); // 64位整数用 %I64d    //printf("进度: %d / %d \n", (int)copied, (int)total); // 文件大小于2G时,可以转成int    return PROGRESS_CONTINUE;}int main(){    const char* source = "c:\\test\\2.rmvb";    const char* dst    = "c:\\test\\2_copy.rmvb";    printf("start copy ...\n");    // 将函数指针传给CopyFileEx    BOOL result = CopyFileEx(source, dst, &CopyProgress, NULL, NULL, 0);    printf("operation done : %s \n", result ? "success" : "failed");    return 0;}

CopyProgress函数很好的体现了回调机制。
//
3.回调机制的补充
(1)回调函数的上下文
回调函数中总有一个参数传递上下文信息。
如:BOOL WINAPI CopyFileEx(…….,lppRoGress_Routine lpProgressRoutine,LPVOID lpData,…)
lp对象是指针类型;
上下文实现的是透传机制,API不关心上文对象的类型(void *),
定义上下文对象:

    Struct Context{    char username[32];    char source[128];    char dst[128];};主函数中:Context ctx;strcpy(ctx.username,"张三");strcpy(ctx.source,"C:\\kt.mp3");strcpy(cx.dst,"D:\\jia.mp3");BOOL result = CopyFileEx(ctx.source,ctx.dst,&CopyProgress, &ctx,NULL, 0);回调的函数的上下文:Context* ctx = (Context*) lpData;

注:(1)上下文对象实现“透传”(void *);
(2)注意:上下文生命周期(对象函数必须是有效的);
(2)C++里的回调实现
.h文件中:

#ifndef _APCOPY_H#define _APCOPY_Hclass AfCopyFileListener{public:    virtual int OnCopyProgress(long long total, long long transfered) = 0;};class AfCopyFile{public:    int DoCopy(const char* source,         const char* dst,         AfCopyFileListener* listener);};#endif

要想实现DoCopy,则需要实现AfCopyFileListener接口;
一般接口类写成内部类;
接口实现:

class MainJob : public AfCopyFileListener{public:        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;    }public:    char source[256];    char dst[256];    char user[64];};

缺点:回调的缺点是使逻辑比较混乱。
尽量避免使用回调。

0 0
原创粉丝点击