关于函数指针的一些例子说明

news/2024/11/2 23:34:22/

函数指针是什么?

大家都知道,指针的本质,无非就是一个值,用来指向一个内存的地址。
在一个可执行程序中,函数本身也被加载到内存中,并且也有一个具体的地址。
因此,同样可以用指针来指向一个函数,这种指向函数入口地址的指针,就是函数指针

为什么要使用函数指针?

上面说了,函数指针是一种指向函数的指针,它可以存储函数的地址,并在需要时调用该函数。
函数指针在C++中有很多用途,以下是一些常见的应用场景:

  • 回调函数:函数指针最常用的用途之一是实现回调机制。在回调机制中,一个函数接受另一个函数作为参数,并在某个事件或条件满足时调用它。这在事件驱动编程和异步编程中非常有用。
  • 函数数组:可以创建一个函数指针数组,这样就可以根据索引来调用不同的函数。这在实现基于状态机的程序时非常有用,可以根据状态选择不同的行为。
  • 多态:函数指针可以用来实现运行时多态。通过将函数指针指向派生类的成员函数,可以在基类指针上调用派生类中重写的方法。
  • 动态绑定:函数指针可以用来实现动态绑定,即在运行时决定调用哪个函数。这在需要根据不同情况调用不同函数时非常有用。
  • 接口实现:在没有虚函数的类中,函数指针可以用来模拟接口的行为,允许不同的类通过不同的实现来响应相同的操作。
  • 优化代码:在某些情况下,使用函数指针可以提高代码的执行效率,尤其是在需要频繁调用函数的情况下,通过函数指针直接调用可以减少函数查找的时间。
  • 信号和槽机制:在Qt等框架中,函数指针用于实现信号和槽机制,允许对象之间的松耦合通信。
  • 函数工厂:函数指针可以用来创建函数工厂,即根据输入参数动态创建并返回不同类型的函数。
  • 装饰器模式:在设计模式中,函数指针可以用来实现装饰器模式,允许在不修改原有函数的情况下增加额外的功能。
    等等。
    函数指针是C++中一个强大的特性,它提供了一种灵活的方式来引用和调用函数,使得代码更加模块化和可重用。

先来看一个Hello World程序

int main(int argc,char* argv[])
{printf("Hello World!\n");return 0;
}

采用函数调用的形式来实现

这是一种常规的使用方式。

void Invoke(char* s);
int main(int argc,char* argv[])
{Invoke("Hello World!\n");return 0;
}void Invoke(char* s)
{printf(s);
}

用函数指针的方式来实现

如下:

void Invoke(char* s);int main()
{void (*fp)(char* s);    //声明一个函数指针(fp)        fp=Invoke;              //将Invoke函数的入口地址赋值给fpfp("Hello World!\n");   //函数指针fp实现函数调用return 0;
}void Invoke(char* s)
{printf(s);
}

说明

函数指针函数的声明之间唯一区别就是,用指针名(*fp)代替了函数名Invoke,这样这声明了一个函数指针,然后进行赋值语句:

fp=Invoke

就可以进行函数指针的调用了。声明函数指针时,只要函数返回值类型、参数个数、参数类型等保持一致,就可以声明一个函数指针了。
注意,函数指针必须用括号括起来,如下:

void (*fp)(char* s)

函数指针数组

来个例子:

#include <iostream>
#include <string>
using namespace std;typedef void (*FP)(char* s);
void f1(char* s){cout<<s;}
void f2(char* s){cout<<s;}
void f3(char* s){cout<<s;}int main(int argc,char* argv[])
{void* a[]={f1,f2,f3};   //定义了指针数组,这里a是一个普通指针a[0]("Hello World!\n"); //编译错误,指针数组不能用下标的方式来调用函数FP f[]={f1,f2,f3};      //定义一个函数指针的数组,这里的f是一个函数指针f[0]("Hello World!\n"); //正确,函数指针的数组进行下标操作可以进行函数的间接调用return 0;
}

实际中,为了方便,通常用宏定义的方式来声明函数指针,实现程序如下:

typedef void (*FP)(char* s);
void Invoke(char* s);int main(int argc,char* argv[])
{FP fp;      //通常是用宏FP来声明一个函数指针fpfp=Invoke;fp("Hello World!\n");return 0;
}void Invoke(char* s)
{printf(s);
}

后记

c++因为可以直接操作指针,很多时候,可以比java、python、go等高级语言有更多灵活性,所以,在系统层面,还是有其不可替代性的。
关于函数指针的具体应用,慢慢补充。


http://www.ppmy.cn/news/1543996.html

相关文章

4. 类和对象(下)

1. 初始化列表 • 之前我们实现构造函数时&#xff0c;初始化成员变量主要使⽤函数体内赋值&#xff0c;构造函数初始化还有⼀种⽅ 式&#xff0c;就是初始化列表&#xff0c;初始化列表的使⽤⽅式是以⼀个冒号开始&#xff0c;接着是⼀个以逗号分隔的数据成 员列表&#xff0c…

java毕业设计之教学资源库系统的设计与实现(springboot)

项目简介 教学资源库系统的设计与实现实现了以下功能&#xff1a; 教学资源库系统的设计与实现的主要使用者分为&#xff1a;管理员&#xff1a;管理员登陆后可对系统进行全面管理&#xff0c;管理员主要功能模块包括个人中心、教师管理、学生管理、课程信息管理、课程作业管…

如何搭建一部引人入胜的短剧小程序

在移动互联网时代&#xff0c;短剧小程序以其轻便、快捷的特点迅速成为人们消遣娱乐的新宠。无论是在通勤途中、休息时间还是等待间隙&#xff0c;用户都能通过手机轻松观看精彩短剧&#xff0c;享受碎片化时间的娱乐盛宴。如果你是一位对内容创作充满热情的创作者&#xff0c;…

运维监控丨16条常用的Kafka看板监控配置与告警规则

本期我们针对企业运维监控的场景&#xff0c;介绍一些监控配置和告警规则。可以根据Kafka集群和业务的具体要求&#xff0c;灵活调整和扩展这些监控配置及告警规则。在实际应用场景中&#xff0c;需要综合运用多种监控工具&#xff08;例如Prometheus、Grafana、Zabbix等&#…

分布式项目pom配置

1. 父项目打包方式为 pom <packaging>pom</packaging> 2. 父项目版本配置 <properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncod…

编程小白如何成为大神

成为编程大神的过程需要时间、耐心和实践。以下是一些适合大学新生的入门攻略&#xff1a; 1. 确定学习目标 选择语言&#xff1a;选择一门编程语言作为起点&#xff0c;如 Python、Java 或 JavaScript。Python 是初学者的热门选择&#xff0c;因为其语法简洁易懂。设定目标&…

竞赛管理新未来:Spring Boot大学生竞赛平台

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了大学生竞赛管理系统的开发全过程。通过分析大学生竞赛管理系统管理的不足&#xff0c;创建了一个计算机管理大学生竞赛管理系统的方案。文章介绍了大学生竞赛管理…

HarmonyOS第一课 06 构建更加丰富的页面-习题解析

判断题 1. Tabs组件可以通过接口传入一个TabsController&#xff0c;该TabsController可以控制Tabs组件进行页签切换。T 正确(True) 错误(False) 使用 this.tabsController.changeIndex(this.currentIndex); 可以切换页签 WebviewController提供了变更Web组件显示内容的接口…