专栏首页C/C++基础C++函数指针简介

C++函数指针简介

1.函数指针简介

1.1函数指针的用法

简单回顾函数指针的用法。

#include <iostream>
using namespace std;

int add(int i,int j)
{
    return i+j;
}
int main()
{
    //用法一
    int(*addP)(int,int)=add;
    int tmp=addP(2,3);
    //或者
    //int(*addP)(int,int)=&add;
    //int tmp=(*addP)(2,3);

    //用法二
    typedef int(*AddP)(int,int);
    AddP funcP=add;
    tmp=funcP(2,3);

    cout<<tmp<<endl;
}

编译运行结果输出5。定义和使用函数指针,需要注意以下几点。

(1)定义函数指针的语法形式比较复杂,常借助于typedef类型定义符来简化函数指针的定义。

(2)函数名代表了函数的入口地址,在位函数指针赋值时,funcP=add;和funcP=&add;都可以。再利用函数指针实现函数调用时,funcP(2,3); (*funcP)(2,3);都是正确的。

(3)可以使用reinterpret_cast类型转换操作符对不同类型的函数指针进行转换,但需要谨慎操作。当然,也要尽量避免功能过于强大的C风格的强制类型转换。

(4)有一种函数叫做“回调函数”(callback function),可以将毁掉函数理解成通过函数指针调用的函数。

1.2函数指针作为参数传递

当函数指针作为另一个函数的参数传递时,对函数指针的生命可以采用“显示”的方式进行,也可以采用“隐式”的方式进行。见下面具体例子。

#include <iostream>
using namespace std;

int f(){
    return 1;
}

void invoke0(int(*func)()){ //显示声明函数指针
    cout<<(*func)()<<endl;
}

void invoke1(int func()){ //隐式声明函数指针
    cout<<func()<<endl;
}

int main(){
    invoke0(f); 
    invoke1(f);
}

2. 指向类成员函数的函数指针的用法

2.1函数指针指向类静态成员函数

对于外部函数,C++沿用了C语言中对函数指针的定义和使用规范。对于类静态成员函数可以理解成“作用域受限的外部函数”,因此,通过以下以下形式即可将类静态成员函数赋值给函数指针。

函数指针=类名::函数名;

调用函数指针时与调用指向外部函数的函数指针方式相同。

2.2函数指针指向类非静态成员函数

在C++语言中,由于面向对象机制的引入,程序中不但有外部函数,还有类对象的成员函数。对于类的非静态成员函数而言,函数指针要以对象的”成员指针”的形式定义和赋值。

#include <iostream>
using namespace std;

class A{
public:
    int retInt(){
        cout<<"in A member function"<<endl;
        return 100;};
};

int main()
{
    A a;
    int(A::*funcP)()=&A::retInt;
    (a.*funcP)();
}

运行输出结果:In A member function。

(1)当函数指针指向类成员对象时,对函数指针的定义必须加上类名以及::(作用域运算符)标识该函数指针指向哪个类的成员函数。

(2)调用函数指针所指向的类成员函数时,必须同时指明函数所操作的类对象,类似于成员函数的访问。


参考文献

[1]陈刚.C++高级进阶教程[M].武汉:武汉大学出版社,2008[3.7(P106-P110)]

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • C++11新特性——range for

    很多编程语言都有range for语法功能,自C++11起,终于将这个重要功能加入C++标准中。range for语句,可以方便的遍历给定序列中的每个元素并对其...

    Dabelv
  • 认识目标文件的符号

    符号是链接的粘合剂,没有符号无法完成链接。每一个目标文件都会有一个相应的符号表(Symbol Table),表里记录了目标文件用到的所有符号。

    Dabelv
  • C++不要在构造函数和析构函数中调用虚函数

    虽然可以对虚函数进行实调用,但程序员编写虚函数的本意应该是实现动态联编。在构造函数中调用虚函数,函数的入口地址是在编译时静态确定的,并未实现虚调用。但是为什么在...

    Dabelv
  • 八种方法(实现两个数互换),绝了绝了!

    如果有不明白的朋友,可以自己准备三个杯子,一个空杯代表变量t,两个杯子装上水分别代表变量a、b,然后互换一下a、b两个杯子里的水即可明白。

    用户7656790
  • 斯坦纳树小结

    attack
  • 使用Docker运行SQL Server

    现在.net core已经跨平台了,大家也都用上了linux用上了docker。跟.net经常配套使用的SQL SERVER以前一直是windows only,...

    kklldog
  • poj 1094 Sorting It All Out(拓扑排序)

         看了discuss才真正明白这道题到底要让我们干什么,poj的discuss真心强大,通过这道题也明白了原来floyd除了找出任意两点的最短距离外,还...

    用户1624346
  • Matplotlib中的两种绘图API说明

    在Matplotlib库中提供了两种风格的API供开发者使用:一种是Pyplot编程接口(state-based),一种是面向对象对象的编程接口(object-...

    卡尔曼和玻尔兹曼谁曼
  • 那些高级运维工程师,都是怎么给公司省机器的?

    随着项目用户量的快速增长,前期可能由于应用程序设计、数据库设计及架构不当,大多项目会在用户量百万、日志/流水等表过千万、乃至过亿时,出现写入卡顿、查询缓慢、各种...

    CSDN技术头条
  • 推荐几款在线 SQL 模拟器

    SQL Fiddle 支持 MySQL、Oracle、MS SQL、PostgreSQL 等主流数据库,不需要注册即可使用。如图 1 所示,左边栏用于构建表结构...

    白日梦想家

扫码关注云+社区

领取腾讯云代金券