第十天2017/04/21(1、函数指针、❤动态库回调❤)

1、函数指针的语法基础

【函数指针的定义、初始化、使用】

    对函数名去多少个&,都不起作用,都是一样的,都还是它本身test。
    如:test、&test、&&test、&&&test都表示函数的入口地址
同样:
    对函数名去多少个*,都不起作用,都是一样的,都还是它本身test。
    如:test、*test、**test、***test都表示函数的入口地址
/*
定义函数指针:有两种方法
1.方法一
①   C语言中通过typedef为函数类型重命名:typedef 返回类型 FUNC(形参列表);
    typedef  void    FUNC(int ,int );  //先给函数重命名为FUNC
②   用FUNC定义一个FUNC类型的函数指针pointer
    FUNC *pointer; //再用FUNC定义一个FUNC类型的函数指针pointer
2.方法二
    void (*pointer)(int ,int); //直接定义一个函数指针pointer
*/

#include <iostream>
using namespace std;

typedef void FUNC(int);  //给“参数是int,返回类型是int”的函数重命名为FUNC
void test(int i)
{
    cout<<"test()"<<endl;
}
int main()
{
    FUNC *pointer = NULL; //1.用FUNC定义一个函数指针pointer
    pointer = &test; //2.用test函数的入口地址初始化函数指针pointer  //等价于pointer = test;
    (*pointer)(100); //3.此处表示函数调用,其中*pointer表示函数名

    return 0;
}
【同志们,注意了:重点来了】
一个函数的形参、实参如下:
    形参:(已经初始化的)函数指针
    实参:函数指针
可以在这个函数中,通过实参传递给形参,进而找到形参指向的函数的入口地址,就可以调用形参指向的函数了====>总结为:一个函数的形参为函数指针,可以调用该函数指针指向的函数。下面的程序案例只是简单的讲解用法,没有什么实际意义,程序案例见下:
#include <iostream>
using namespace std;

int add(int a,int b)
{
    return a+b;
}

void gg(int (*p)(int,int),int a,int b) //函数指针作函数参数
{//在这个函数里面,可以通过这个函数指针,调用外部的函数,形成一个回调
    cout<<(*p)(a,b)<<endl; //在被调函数中,使用传入的函数指针
}
int main()
{
    int (*p)(int,int); //定义一个函数指针
    p = &add; //初始化函数指针
    gg(p,1,2); //函数指针作形参
}
==================================================================================
【讲解】正常情况下,我们都是去调用动态库的代码,但是有一天,动态库的代码要调用我们写的代码,这样就形成了回调!
加载动态库的两种方式:
1.静态调用:编译器帮我们加载
2.动态调用:自己手工的加载

    HINSTANCE hDll;//定义一个句柄
    hDll=LoadLibrary("F:\\DLL.dll");//1.动态加载DLL模块句柄:加载动态库

    if(hDll) //如果加载成功
    {
        //2.定义一个函数指针,去接受获得的GetProcAddress函数返回的函数的入口地址
        typedef int (*pAdd)(int,int) = NULL; //定义一个函数指针类型pAdd
        pAdd ptr = (pAdd)GetProcAddress(hDll,"add");;//用函数指针类型pAdd,去定义一个函数指针变量ptr
        if(ptr)
        {
            int result=ptr(2,3);
            printf("%d",result); 
        }
        FreeLibrary(hDll);//释放已经加载的DLL模块
    }

—————————————————————————————————————————-
【动态库回调函数的实现的两种方式】

如何把一个普通的DLL动态库变成一个业务模型,需要做的工作
    需要把第三方业务入口传进来(即回调函数的入口地址传进来),传进来的方式有两种:
    方式一:回调函数的入口地址直接放在DLL中的参数中
    方式二:回调函数的入口地址缓存到框架库中


【方式一案例】
/*
Question1:如何实现了上层的业务数据数组的遍历?
ANSWER1:
STL不知道上层的业务数据类型是什么样的,因此写出遍历上层的业务数据的函数callbackFunc_for_each,
再用STL中的for_each函数去回调callbackFunc_for_each函数---->这样就实现了上层的业务数据数组的遍历。
Question1:如何实现了上层的业务数据数组的排序?
ANSWER1:
STL不知道上层的业务数据类型是什么样的,因此写出排序上层的业务数据的函数callbackFunc_sort,
再用STL中的sort函数去回调callbackFunc_sort函数---->这样就实现了上层的业务数据数组的排序。
*/
【代码见下】
#include <iostream>
#include <vector>
#include <algorithm>  
using namespace std;

struct teacher
{
    char name[100];
    int age;
};

void callbackFunc_for_each(struct teacher& t) //回调函数
{
    cout<<t.name<<"  "<<t.age<<endl;
}
int callbackFunc_sort(struct teacher& t1,struct teacher& t2)//回调函数
{
    return t1.age>t2.age;
}

int main()
{
    struct teacher t1 = {"T1",30};
    struct teacher t2 = {"T2",40};
    struct teacher t3 = {"T3",50};

    vector<struct teacher> vec;
    vec.push_back(t1);
    vec.push_back(t2);
    vec.push_back(t3);
//【解释】for_each是DLL中的函数,要使for_each函数适应于所有的业务模型,应当利用
//回调函数callbackFunc_for_each,该回调函数是自己手工写的!
    for_each(vec.begin(),vec.end(),callbackFunc_for_each); //callbackFunc_for_each是回调函数
    sort(vec.begin(),vec.end(),callbackFunc_sort); //callbackFunc_sort是回调函数
    for_each(vec.begin(),vec.end(),callbackFunc_for_each);
}

【方式二案例】
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值