C++经典问题_09 函数指针

一. 函数的类型和地址

函数也是有类型的,函数的类型由它的返回类型和形参类型共同决定,与函数名无关.
比如下面的函数的类型

bool lengthCompare(const string & a,const string & b);

该函数的类型是bool (const string&,const string&);
和变量一样,函数有固定的地址,直接打印函数名,或者函数的取地址符号,都能打印函数的地址.

/*----------------------------------------------------------------
* 项目: Classical Question
* 作者: Fioman
* 邮箱: geym@hengdingzhineng.com
* 时间: 2022/3/22
* 格言: Talk is cheap,show me the code ^_^
//----------------------------------------------------------------*/

#include <iostream>
using namespace std;
void func(void)
{

}

int main()
{

	cout << "直接通过名称打印地址: " << func << endl;
	cout << "通过地址符号打印地址: " << &func << endl;
	cout << "通过解引用法打印地址: " << *func << endl;
	cout << (func == &func) << endl;
	cout << (&func == *func) << endl;
	system("pause");
	return 0;
}

从上面的例子可以看出来:
func函数名称 和&func以及*func代表的意思都是一样的,都表示的是一个地址,指向保存函数的地址.

二. 函数指针的定义方式

① 函数指针的声明

把函数名替换为指针变量,就是声明一个可以指向该函数的指针.

bool (*pf)(const string&,const string&); // 未初始化

pf指向一个函数,该函数的参数是两个const string的引用,返回值是bool类型

*pf两边的括号不能少,如果不写括号,则pf是一个返回值为bool指针的函数

bool *pf(const string&,const string&);
② 当我们把函数名作为一个值使用时,该函数自动转换为指针
int (*funcPtr)(); // 函数指针的声明
int (*const funcPtr)(); // 指针指向的函数的返回值是常量
/*----------------------------------------------------------------
* 项目: Classical Question
* 作者: Fioman
* 邮箱: geym@hengdingzhineng.com
* 时间: 2022/3/22
* 格言: Talk is cheap,show me the code ^_^
//----------------------------------------------------------------*/

#include <iostream>
using namespace std;
int foo()
{
	cout << "foo() 函数被调用!" << endl;
	return 100;
}

int func()
{
	cout << "func() 函数被调用!" << endl;
	return 200;
}

int main()
{

	// 首先声明一个函数指针
	int (*funcPtr)() = foo; // funcPtr指向了foo;
	funcPtr(); // 可以直接调用
	(*funcPtr)(); // 也可以解引用调用
	//(&funcPtr)(); // 这样调用不行
	funcPtr = func; // 指针指向了func函数,但是不能写成是
	funcPtr();
	(*funcPtr)();

	//funcPtr = func(); // 不能这么调用,这样调用的话funcPtr指向了200这个值了,但是如果func返回的是一个函数指针,也是可以这么调用的
	system("pause");
	return 0;
}

结果:

③ 函数指针在使用的时候注意事项

1. 函数指针声明的形参和返回类型必须和指向的那个函数的形参和返回类型一样,如果不一样就会报错

/*----------------------------------------------------------------
* 项目: Classical Question
* 作者: Fioman
* 邮箱: geym@hengdingzhineng.com
* 时间: 2022/3/22
* 格言: Talk is cheap,show me the code ^_^
//----------------------------------------------------------------*/

#include <iostream>
using namespace std;
int func(int a)
{
	cout << "func() 被调用!" << endl;
	return a;
}

void func_1(int a)
{
	cout << "func_1() 被调用!" << endl;
}



int main()
{
	int (*funcPtr)(int a);
	funcPtr = func; // 正确,类型匹配
	funcPtr(10);
	//funcPtr = func_1; // 错误,返回类型不匹配
	void (*funcPtr1)(int a);
	funcPtr1 = func_1; // 正确,类型匹配
	//funcPtr1 = func; // 错误,类型不匹配
	funcPtr1(10);
	system("pause");
	return 0;
}

2. 重载函数的指针

当我们使用重载函数的时候,上下文必须清晰地界定到底应该选用哪个函数.

void func(int*);
void func(unsigned int);

void (*pf1)(unsigned int) = func; // pf1指向 func(unsigned int);
void (*pf2)(int) = func; // 错误: 没有任何一个func与该形参类型匹配
double (*pf3)(int*) = func; // 错误: pf3的func(int*)的返回类型不匹配.

三. 函数指针形参和返回值

① 形参可以是指向函数的指针,形参看起来是函数类型,实际上却是当成指针来使用

有两种方式声明:

  1. 直接使用函数类型,会自动转换成指向函数的指针
  2. 显示的将形参定义成指向函数的指针
/*----------------------------------------------------------------
* 项目: Classical Question
* 作者: Fioman
* 邮箱: geym@hengdingzhineng.com
* 时间: 2022/3/22
* 格言: Talk is cheap,show me the code ^_^
//----------------------------------------------------------------*/

#include <iostream>
using namespace std;

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

// 形参直接是函数类型,会默认转换为函数指针
void func(int e, int d, int foo(int a, int b))
{
	// 这里的func会直接转换为int (*func)(int a,int b)),函数类型直接转换为函数指针来使用
	cout << "函数调用结果: " << foo(e, d) << endl;
}

// 形参直接是函数指针
void func_02(int e, int d, int (*foo)(int, int))
{
	cout << "函数调用结果: " << foo(e, d) << endl;
}

int main()
{
	func(10, 20, add); // 直接调用加法,形参里面的foo会转换为函数指针
	func_02(10, 20, sub); // 形参里面的foo直接就是函数指针
	system("pause");
	return 0;
}

② 返回指向函数的指针
  1. 首先返回值不能是一个函数,但是可以值返回指向函数类型的指针.
  2. 我们必须要将返回类型写成指针的形式,编译器不会自动地将函数返回类型当成对应的指针类型来处理.
using F = int(int*,int); // F是函数类型,不是指针
using PF = int(*)(int*,int); // PF是指针类型

必须时刻注意: 函数的返回类型必须显示的转换为函数指针类型编译器不会自动进行转换

PF f1(int); // 正确: PF是指向函数的指针,f1返回指向函数的指针
F f1(int); //  错误: F是函数类型,f1不能返回一个函数
F * f1(int); // 正确: 显示的指定f1的返回类型是指向函数的指针

四. 使用typedef 来定义函数类型以及函数指针类型

// Func 和 Func2是函数类型
typedef bool Func(const string&,const string&);
typedef decltype(lengthCompare) Func2;  // 等价的类型

typedef bool(*FuncP)(const string&,const string&);
typedef decltype(lengthCompare) * *FuncP2; // 等价的类型

上例中, FuncFunc2是函数类型,而FuncP以及FuncP2是指针类型.注意decltype()是返回函数的类型,此时不会将函数类型转换为指针类型.

// useBigger的等价声明,其中使用了上面的类型别名
void useBigger(const string&,const string&,Func);
void useBigger(const string&,const string&,FuncP2);
/*----------------------------------------------------------------
* 项目: Classical Question
* 作者: Fioman
* 邮箱: geym@hengdingzhineng.com
* 时间: 2022/3/22
* 格言: Talk is cheap,show me the code ^_^
//----------------------------------------------------------------*/


#include <iostream>
using namespace std;
typedef int (*funcPtr)(int, int); // 定义一个函数指针指针类型是 int (int,int) 返回值为int,参数是int类型的函数指针funcPtr

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

int sub(int a, int b)
{
	return a - b;
}

int mul(int a, int b)
{
	return  a * b;
}

int divison(int a, int b)
{
	return b ? a / b : -1;
}

// 定义一个函数,参数是op,返回一个指针,该指针类型为拥有两个int参数,返回类型是int的函数指针.
funcPtr calc_func(char op)
{
	switch (op)
	{
	case '+':
		return add;
	case '-':
		return sub;
	case '*':
		return mul;
	case '/':
		return divison;
	default:
		return NULL;
	}
}

// 直接定义一个函数指针.
int (*s_calc_func(char op)) (int, int)
{
	return calc_func(op);
}

int calc(int a, int b, char op)
{
	funcPtr fp = calc_func(op);
	int (*s_fp)(int, int) = s_calc_func(op); // 和上面的等价
	cout << "fp: " << fp << ",s_fp: " << s_fp << endl;
	return fp(a, b);
}

int main()
{
	int a = 100, b = 200;
	cout << a << '+' << b << "=" << calc(a, b, '+') << endl;
	cout << a << '-' << b << '=' << calc(a, b, '-') << endl;
	cout << a << "*" << b << '=' << calc(a, b, '*') << endl;
	cout << a << "/" << b << "=" << calc(a, b, '/') << endl;

	system("pause");
	return 0;
}

结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值