C++函数指针

指针是表示内存中(虚拟)地址的标识符

对于一个函数,它的函数名就代表了这段代码的地址

复制代码
double multiplay(double a,double b)
{
	return a*b;
}

cout<<hex<<(unsigned long long) multiplay<<endl;  //输出:40157f

定义函数指针

采用如下方式定义函数指针:

复制代码
返回类型 (*函数指针名)(参数列表)

不能把包裹 *函数指针名的括号拿掉,不然就变成了定义指针函数的语法

定义函数与定义函数指针

为了方便方便记忆,我们来看看定义函数和定义函数指针的有哪些联系:

复制代码
函数签名
double multiplay(double a,double b)

↓ 将函数名替换成 (*指针名),就完成了函数指针的定义
double (*ptr)(double a,double b)

↓ 由于参数名对指针没有意义,可以进一步去掉
double (*ptr)(double,double)
使用函数指针调用函数
复制代码
double multiplay(double a,double b)
{
	return a*b;
}
double add(double a,double b)
{
	return a+b;
}
//...
//函数指针指向函数,既可以直接赋予 函数名,也可以赋予 函数名+取地址运算符
double (*ptr1)(double,double) = multiplay;
double (*ptr2)(double,double) = &add;

//调用函数时,既可以用函数指针+参数的方式,也可以用括号+解引用运算符+函数指针+参数的方式
cout<<ptr1(4,5)<<endl;
cout<<(*ptr1)(4,5)<<endl;

//注意:此种写法相当于对函数返回值解引用,会导致错误
cout<< *ptr1(4,5) <<endl;   //相当于*(ptr1(4,5))
使用函数指针更改指向

在定义函数指针时,定义的是一个指针指向的函数的形式

因此对于返回值与参数相同的函数,可以使用这样的指针来指向

复制代码
double multiplay(double a,double b)
{
	return a*b;
}
double add(double a,double b)
{
	return a+b;
}
//...

double (*ptr)(double,double) = multiplay;
cout<< ptr(4,5)<<endl;       //输出:20
ptr = &add;
cout<< ptr(4,5)<<endl;       //输出:9
使用typedef给函数指针定义别名

前面的定义方式看起来比较繁琐,可以使用typedef定义类型别名进行简化

复制代码
//在定义函数指针的语法前加上typedef
//这时FuncPtr就不再是一个函数指针,而表示这种指针的类型
typedef double (*FuncPtr)(double,double)

//在后续使用时,就可以使用这个类型定义指针
FuncPtr ptr = multiplay;

//也可以用typedef定义一个没有指针的函数类型
typedef double (MyFuncType)(double,double)

//在后续使用时,使用指针的形式定义函数
MyFuncType* ptr = multiplay;
使用auto 自动类型推断
复制代码
double multiplay(double a,double b)
{
	return a*b;
}
double add(double a,double b)
{
	return a+b;
}
//...
typedef double (*FuncPtr)(double,double)

//可以使用auto自动推断出函数指针类型
auto ptr1 = multiplay;
cout<< ptr1(4,5) << endl;

//但auto不能推断函数指针数组
// auto ptrs[2] = {multiplay, add};  //错误
FuncPtr ptrs[2] = {multiplay, add};  //这时需要使用 函数指针类型 进行定义
cout<< ptrs[0](4,5) << endl;      
函数指针的使用

函数指针可以用作回调函数

复制代码
bool compare(float a,float b)
{
	return a<b;
}

int main()
{
	vector<float> numbers{0,1,3,0,0,4,9};
	sort(numbers.begin(),numbers.end(),compare);
	for(auto number:numbers) cout<< number <<" ";
	return 0;
}
题外话: 仿函数/函数对象

不过现在来说,更倾向于使用函数对象做回调

复制代码
class Compare
{
public:
	Compare(float a,float b) { }
	bool operator()(float a,float b)
	{
		return a<b;
	}
};

int main()
{
	vector<float> numbers{0,1,3,0,0,4,9};
	sort(numbers.begin(),numbers.end(),Compare());
	for(auto number:numbers) cout<< number <<" ";
	return 0;
}

补充一个易混点

复制代码
需要注意的是sort中的Compare()是创建一个对象,仿函数在sort内部调用
一般来说,使用类名()时 是在创建对象,使用对象名()时 是在调用仿函数
Compare comp;
Compare(1,2);       //创建一个临时对象
comp(1,2);          //调用函数
Compare(1,2)(1,2);  // 创建一个临时对象并调用函数

仿函数的最大优势在于,它可以有自己的状态

复制代码
class AddANum
{
public:
    int Num;
    int operator()(int x) const { return x + Num; }
};
类成员函数指针

类成员函数指针的定义方法:

复制代码
返回类型 (类名::*函数指针名称)(参数列表);

class Calc
{
	public:
	double multiplay(double a,double b){ return a * b; }
	double add(double a,double b){ return a + b; }
};
int main()
{
	//给类成员函数指针赋值时前面建议加上& 不加&有的编译器会报错
	double (Calc::*PtrMemberFunc)(double,double) = &Calc::multiplay;

	//如下演示了使用对象和指针调用函数,语法要一致 括号的位置要一致、*号也不能丢 
	Calc c1;
	cout<<(c1.*PtrMemberFunc)(4,5)<<endl;    //结果:20
	
	PtrMemberFunc = &Calc::add; 
	Calc* c2 = &c1;
	cout<<(c2->*PtrMemberFunc)(4,5)<<endl;   //结果:9
	
	return 0;
}
类成员函数指针仍然具有多态性
复制代码
class BaseClass
{
public:
	virtual void print(){ cout<<"Base class"<<endl;	}
};

class SubClass :public BaseClass
{
public:
	virtual void print() override { cout<<"Sub class"<<endl;	}
};

int main()
{
	void (BaseClass::*pMenFunc)() = &BaseClass::print;
	
	BaseClass* obj = new SubClass();
	(obj->*pMenFunc)();              //输出:Sub class
}
相关推荐
威桑2 小时前
解决 Qt6 程序 在Linux 环境下无法输入中文的问题
linux·c++·qt
浅念-2 小时前
C++ :类和对象(4)
c语言·开发语言·c++·经验分享·笔记·学习·算法
shentuyu木木木(森)2 小时前
栈与队列基础
c++··队列
yuuki2332332 小时前
【C++】模拟实现 AVL树
java·c++·算法
蜡笔小马3 小时前
20.Boost.Geometry 中常用空间算法详解:crosses、densify、difference 与离散距离度量
c++·算法·boost
Mr YiRan3 小时前
C++语言学习之面向对象
java·c++·学习
寻寻觅觅☆4 小时前
东华OJ-基础题-127-我素故我在(C++)
开发语言·c++·算法
ab1515174 小时前
2.13完成101、102、89
开发语言·c++·算法
HAPPY酷4 小时前
C++中类常见的函数分类
java·开发语言·c++