C++函数指针

函数指针的调用:

调用函数的两种方式:

  • 直接调用:通过函数名(函数的入口地址)直接调用
  • 间接调用:通过函数指针指向函数间接调用
cpp 复制代码
void(*p_fun)(int)=&fun; //定义变量并初始化
p_fun = &fun; //赋值,指向一个函数
(*p_fun)(10); //间接调用函数
cpp 复制代码
#include <iostream>
using namespace std;

// 定义一个函数,接受一个整数参数并打印
void show(int a) {
    cout << "show(int)" << " " << a << endl;
}

// 定义一个函数,接受一个函数指针作为参数
void fun_show(void (*p_fun)(int)) {
    (*p_fun)(30); // 通过函数指针调用传入的函数
}

int main() {
    show(10); // 直接调用 show 函数,输出: show(int) 10

    // 定义一个函数指针并初始化,使其指向 show 函数
    void (*p_fun)(int) = &show; 
	//定义函数指针且初始化,可以不加取地址符号,因为函数名就是函数地址
    (*p_fun)(20); // 可以用这行代码间接调用 show 函数,输出: show(int) 20
    
    // 直接调用函数指针 p_fun
    p_fun(20); // 使用函数指针 p_fun 调用 show 函数,输出: show(int) 20

    // 将函数指针 p_fun 赋值为 show 函数(可以省略取址符号 &)
    p_fun = &show; // 赋值(&show 是可选的)
    
    // 调用 fun_show,并将函数指针 p_fun 作为参数传递
    fun_show(p_fun); // 输出: show(int) 30

    return 0;
}

函数指针有时看起来比较繁琐、可读性差一些,我们可以用typedef进行优化

cpp 复制代码
typedef void(*P_FUN)(int);
P_FUN p_fun = &fun;
cpp 复制代码
//将函数指针用typedef进行优化
#include <iostream>
using namespace std;

// 定义一个接受一个整数参数并打印的函数
void show(int a) {
    cout << "show(int)" << " " << a << endl;
}

// 使用 typedef 优化函数指针的定义
typedef void (*P_FUN)(int);

// 定义一个函数,接受一个函数指针作为参数
void fun_show(P_FUN p_fun) {
    (*p_fun)(30); // 通过函数指针调用传入的函数,并传入 30
}

int main() {
    P_FUN p_fun = &show; // 使用 typedef 定义的函数指针并指向 show 函数
    fun_show(p_fun); // 调用 fun_show,并传入 p_fun
    return 0;
}

使用函数指针调用函数的好处:

函数指针可以实现同一功能的多个模板统一标识起来,是系统结构清晰,后期更容易维护,便于分层设计,利于系统抽象,降低耦合,使接口与实现分离,提高代码的复用性,扩展性

嵌套函数指针:

cpp 复制代码
#include <iostream>
using namespace std;

/*
func :函数名 挨着函数名的第一个括号里是参数
参数列表:(char*, void(*)(bool, double*)) ,两个参数,参数1:char*
参数2:void(*)(bool, double*)
返回值:void (*)(int*, void* (char, bool*)),返回值是函数指针,指向的函
数:void (int*, void* (char, bool*))
*/

// 定义函数指针类型
typedef void(*P_PARAM)(bool, double*); // P_PARAM 指向接受 bool 和 double* 的函数
typedef void* F_PARAM(char, bool*); // F_PARAM 指向接受 char 和 bool* 的函数并返回 void*
typedef void (*P_RET)(int*, F_PARAM f); // P_RET 指向接受 int* 和 F_PARAM 的函数

// func 函数定义,接受 char* 和一个函数指针
void (*func(char*, void(*)(bool, double*)))(int*, void* (char, bool*)) {
    cout << "优化前函数" << endl;
    return nullptr; // 返回值应为 nullptr,表示没有返回有效指针
}

// func1 函数定义,接受 char* 和 P_PARAM 类型函数指针
P_RET func1(char*, P_PARAM p1) {
    cout << "优化后函数" << endl;
    return nullptr; // 返回值应为 nullptr,表示没有返回有效指针
}

int main() {
    char* p = new char[1](); // 动态分配一个字符数组
    P_PARAM p11 = nullptr; // 初始化函数指针 p11 为 nullptr
    P_RET pRet = func(p, p11); // 调用 func 函数
    pRet = func1(p, p11); // 调用 func1 函数
    delete[] p; // 释放之前分配的内存
    return 0;
}

类成员函数指针:

类成员函数与普通的函数的区别:

  1. 所属的作用域不同,类成员函数标识了所属的类,必须通过对象调用(虽然可以是空指针对象,但必须得有)。
  2. 类成员函数编译器会默认加上一个隐藏的参数: this指针。所以定义类成员函数的指针与普通的函数指针肯定会有所区别:C++ 提供了三种运算符 ::* 、.*、 ->. 用于定义和使用类成员函数指针。
  3. 类成员函数指针的&取地址符号不可省略,而普通函数的可以。
cpp 复制代码
::* :定义类成员函数指针
.* :用对象通过类成员函数指针调用指向的函数
->* :用指针对象通过类成员函数指针调用指向的函数
注:
类成员函数指针的定义一定是 void (CTest ::* p_fun)(int a) = &CTest::show;
而不是 void (CTest ::(*p_fun)(int a) = &CTest::show;

类成员函数定义与调用:

cpp 复制代码
#include <iostream>
using namespace std;
class CTest {
	public:
		void show(/* CTest * const this */int a) {
			cout << this << endl; //输出tst的地址
			cout << "CFather::show" << a << endl;
		}
};
int main() {

	void (CTest::*p_fun)(int a) = &CTest::show;
//定义类成员函数指针并初始化,注意:& 和类名作用域 都不能省略,

//优化
	typedef void (CTest::*P_FUN)(); //使用typedef 进行优化
	P_FUN p_fun2 = &CTest::show;

//定义
	CTest tst;
	CTest*pTst = new CTest;
	CTest* pTst = &tst;

//调用
	(pTst->*p_fun)(20);
	(tst.*p_fun2)(); //普通对象通过指针调用类成员函数
	(pTst->*p_fun2)(); //指针对象通过指针调用类成员函数

}

仿写多态:

可以用类成员函数指针来模拟实现多态。用父类指针调用子类函数

cpp 复制代码
#include <iostream>
using namespace std;
class CPeople {
	public:
		int m_money;
		CPeople() {
			m_money = 10;
		}
		void cost(int n) {
			m_money -= n;
		}
		void show() {
			cout << "m_money:" << m_money << endl;
		}
};
class CYellow :public CPeople {
	public:
		void eat() {
			cout << "用筷子夹菜吃饭" << endl;
		}
};
class CWhite :public CPeople {
	public:
		void eat() {
			cout << "用刀叉吃肉" << endl;
		}
};
class CBlack :public CPeople {
	public:
		void eat() {
			cout << "用手抓饭" << endl;
		}
};
typedef void(CPeople::* P_FUN)();
void fun(CPeople* p, P_FUN p_fun) {
    p->cost(1);
    p->show();
    (p->*p_fun)(); // 调用成员函数
}
	//CPeople* p,这是一个指向 CPeople 类对象的指针。
	//由于 CPeople 是一个基类,p 可以指向任何 
	//CPeople 的派生类对象(例如 CYellow、CWhite、CBlack),
	//这体现了多态性的特性。
	
	//P_FUN p_fun,这是一个指向 CPeople 类成员函数的指针。
	//P_FUN 是之前定义的类型别名,表示返回类型为 void,
	//且没有参数的成员函数指针。通过传递这个指针,
	//可以在 fun 函数内部调用特定的成员函数。

int main() {
	CPeople* pPeo = new CYellow;
	typedef void(CPeople::* P_FUN)();
//void(CPeople:: * p_fun)() = (void(CPeople::*)())&CYellow::eat;
    P_FUN p_fun = (P_FUN)&CYellow::eat; // 获取 CYellow::eat 的指针
//通过强转指向子类的函数
    (pPeo->*p_fun)(); // 调用 eat 方法
    fun(new CWhite, (P_FUN)&CWhite::eat); // 调用 CWhite 的 eat 方法
    fun(new CBlack, (P_FUN)&CBlack::eat); // 调用 CBlack 的 eat 方法
    return 0;
}
相关推荐
Swift社区2 分钟前
Swift 解法详解:LeetCode 367《有效的完全平方数》
开发语言·leetcode·swift
蒋星熠1 小时前
Python API接口实战指南:从入门到精通
开发语言·分布式·python·设计模式·云原生·性能优化·云计算
还梦呦1 小时前
2025年09月计算机二级Java选择题每日一练——第十一期
java·开发语言·python·计算机二级
完美世界的一天1 小时前
Golang 面试题「初级」
开发语言·面试·golang
MOS管-冠华伟业1 小时前
微硕WINSOK高性能N&P沟道MOS管WSP4067在Type-C双向快充电源管理系统中的应用
c语言·开发语言
振鹏Dong3 小时前
Spring注解演进与自动装配原理深度解析:从历史发展到自定义Starter实践
java·开发语言
LCY1333 小时前
整理python的高级用法
开发语言·python
专注VB编程开发20年3 小时前
C# .NET支持多线程并发的压缩组件
开发语言·前端·c#·.net·多线程·zip·压缩
lightqjx4 小时前
【C++】类和对象 --- 类中的6个默认成员函数
开发语言·c++
How_doyou_do4 小时前
JS之刷刷
开发语言·javascript·ecmascript