函数指针详解

普通函数指针

  1. 函数指针的定义方式
    return_type (*name)(arg1, arg2,...., agrn)

函数指针的组成和函数签声明定义无多大规则,仅仅只需要在函数名字签名加上*, [返回值+(*函数指针名字)+(参数列表)]
其中括号是必须的。
2. 函数指针的赋值及调用
函数指针在使用前是必须赋值的,赋值就很容易了,只需要知道函数名字和数组名字一样,都代表首地址,即函数名字代表函数的首地址,数组名字代表数组首地址。调用函数时候仅仅使用() 操作符就可以调用函数了,和使用函数名字调用函数大同小异

```cpp
#include <iostream>
void foo() // 定义无参无返回值函数
{
    std::cout << "call foo function." << std::endl;
}

int add(int a, int b)
{
    return a + b;
}
int main()
{
    void (*pfoo)(); // 定义名字为fp的函数指针
    pfoo = foo; // 对函数指针赋值 函数名字即是函数指针的地址
    pfoo(); // 调用函数指针 使用括号操作符

    int (*padd)(int, int); // 两个参数函数指针定义
    int (*padd_arg_name)(int a, int b); // 也可以写成 参数名字可有可无
    padd = add; // 赋值
    padd_arg_name = add;

    int ret = padd(4, 5); // 调用
    int ret_arg_name = padd_arg_name(4, 5);
    return 0;
}
```
  1. 使用typedef简化函数指针定义
    typedef 是c++ 提供的关键字,重定义别名, typedef typename 就是 重定义一种还没有确定的类型的别名。typedef T U, 就是把T这种类型重定义别名为U。
    例如:
    typedef char byte; // 将char 使用别名byte代替
    typedef int  int32_t; // 将int 使用别名int32_t代替
    
    函数指针也是一种类型,可以理解为无参的函数指针,一个参数的,两个参数的,参数类型又可以不相同,就可以组成无穷无尽的函数指针,并将某个函数指针使用typedef 简化后,更方便阅读和理解。可以举个四个参数的函数指针。
    int (*draw_rect)(int x, int y, int width, int height); // 指向绘制一个矩形的函数指针
    typedef int (*draw_rect)(int x, int y, int width, int height); 
    
    这里使用的是typedef 的特殊用法,不像常规用法那样 typedef 老变量名 新变量名。
    typedef 的特殊用法用三种: 即数组别名, struct 别名, 函数指针别名。
    • 数组别名
    typedef int Point[2]; // 将int [2] 这种类型当做别名Point
    Point point;
    int x = 1, y = 2;
    point[0] = x;
    point[1] = y;
    std::cout << point[0] << " " << point[1] << std::endl;
    
    数组这种特殊的别名就是数组的名字。
    其实定义别名的时候去掉typedf和别名, 剩下的就是原来变量的类型。
    typedef int Point[2] 去掉typedef 和 Point,剩下int[2] ,即int 类型的两个元素数组。
    • 结构体别名
    typedef struct 
    {
        int x;
        int y;
    } Point; // 去掉typedef 和Point 剩下的是一个结构体
    
    typedef struct Point_
    {
    
    } Pt;
    
    • 函数指针别名
      函数指针和数组有莫大关系,比如名字代表首地址。那么别名规则也是一样的,
    // 去掉别名和typedef 代标的类型是int(*)(int x, int y, int width, int height) 妥妥一个函数指针的样子
    typedef int (*draw_rect)(int x, int y, int width, int height);
    
    使用typedef别名之后,理解函数指针变量就很轻松了,本来函数指针长void(*fp)()这个样子。那么我想定义多个这种变量只能这样写。
    void(*fp)();
    void(*fp_1)();
    void(*fp_2)();
    
    // 赋值 函数名字即地址
    fp = foo;
    fp_1 = foo;
    fp_2 = foo;
    
    这种方式对于代码阅读和书写总不友好,哪有变量名字写在中间的,一般不都是类型+ 变量名这种书写习惯,所以使用tyepdef后
    typedef void(*fp)();
    fp p1; // 此种方式就是很好理解了,符合大多数人的习惯。
    fp p2;
    fp p3;
    // 赋值
    p1 = foo;
    p2 = foo;
    p3 = foo;
    
  2. 函数指针数组
    数组就是存储相同的类型,既然函数指针是一种类型,那么肯定是可以使用数组存储的。
    #include <iostream>
    
    int add(int a, int b)
    {
        std::cout << "call add." << std::endl;
        return a + b;
    }
    
    int sub(int a, int b)
    {
        std::cout << "call sub." << std::endl;
        return a - b;
    }
    
    
    int main()
    {
        typedef int (*Fun)(int a, int b); // 同时表示加减法
        // 函数指针别名数组
        Fun add_sub[2] = { 0 }; // 20个元素全部初始化为nullptr
        add_sub[0] = add;
        add_sub[1] = sub;
        for (int i = 0; i < 20; i++)
        {
            int index = i % 2; // 循环调用数组中第一个元素和第二个元素
            add_sub[index](i, i);
        }
    
        std::cout << "奇怪的写法" << std::endl;
        int (*pFun[2])(int a, int b); // 这种写法很奇怪,一般不容易理解
        pFun[0] = sub;
        pFun[1] = add;
        for (int i = 0; i < 20; i++)
        {
            int index = i % 2; // 循环调用数组中第一个元素和第二个元素
            pFun[index](i, i);
        }
        return 0;
    }
    

类成员函数指针

类静态函数指针
  1. 静态函数指针的定义方式
    定义方式与普通函数定义方式大同小异,仅仅是赋值的时候需要使用&类名:函数名
    #include <iostream>
    
    class Foo
    {
    public:
        static void foo()
        {
            std::cout << "call static funciton foo." << std::endl;
        }
    };
    
    int main()
    {
        void (*pf)(); // 与普通函数指针无区别
        pf = &Foo::foo; // 赋值需要使用取地址符
        pf(); // 调用与普通指针无区别
        return 0;
    }
    
  2. 静态函数指针与普通指针的区别
    唯一的区别就是需要使用&类名:函数名获取函数地址,类的静态成员函数不在代表函数指针的首地址。
类成员函数指针
  1. 定义
    类成员函数指针的定义仅仅需要加上类的命名空间如下:
    // [返回值](类名::*函数指针名字)(参数列表)
    return_type (className::*pf)(arg list)
    
  2. 赋值
    赋值与函数指针的区别是使用&类名::函数名获取地址。
  3. 调用
    调用分为两条:
    1. 是一个对象实例调用:.* (类对象.*指针名)(参数列表) 其中两个()是必须要的,第一个括号代表优先级,第二个括号代码调用
    2. 是一个对象指针: ->* (类指针->*指针名)(参数列表) 其中两个()是必须要的,第一个括号代表优先级,第二个括号代码
  4. 示列代码
    #include <iostream>
    
    class Foo
    {
    public:
        static void foo()
        {
            std::cout << "call static funciton foo." << std::endl;
        }
    
        int add(int a, int b)
        {
            std::cout << "call class add ." << std::endl;
            return a + b;
        }
    };
    
    int main()
    {
        int (Foo::*pAdd)(int, int);
        pAdd = &Foo::add;
        
        //pAdd(1, 2);  错误,需要使用类对象或者类指针调用
        Foo f;
        Foo* p = new Foo;
        // f.*pAdd(1, 2); 错误.的优先级太低,需要使用括号获取指针才能调用
        (f.*pAdd)(1, 2); // 正确
        (p->*pAdd)(1, 2);
        typedef int (Foo::* pf)(int, int); // 使用typef
        pf padd = &Foo::add;
        // padd(1, 2); 错误,需要使用类对象或者类指针调用
        (f.*padd)(1, 2); // 对象
        (p->*padd)(1, 2); // 指针
        return 0;
    }
    

函数指针总结

函数指针

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值