概述
本文详细介绍了C/C++中的普通函数和类的成员函数的指针。结合C++代码示例讲解了函数指针作为其他函数的输入、返回值以及typedef如何提高代码可读性的实用技巧。对于类的成员函数(方法)指针,则分为静态和非静态两种情况。最后总结了普通函数、类的非静态成员函数、类的静态成员函数的声明、赋值和定义的C++语法以供查阅。普通函数的指针
声明、定义和赋值
首先让我们来区别以下4条声明语句:int x; // x是一个int型的变量
int *x; // x是一个指向int型变量的指针
int *x(); // x是一个返回int型指针的函数
int (*x)(); // x是一个函数指针,输入参数为空,返回类型为int型指针
因此,把一个名为fun的函数的声明语句变为函数指针变量pfun的声明语句,只需要将 fun 变为 (*pfun),其他的不变即可(注意:小括号必不可少!)。
double fun(string& str1, string &str2); // 函数fun的声明
double (*pfun)(string& str1, string &str2); // 函数指针变量pfun的声明
在C/C++中,数组变量的名字是一个指向该数组元素类型的指针常量(存放首元素的地址),类似地,函数的名字也表示一个指向该函数的指针常量(存放该函数入口地址):
int array[5]; // array是一个指向int的指针常量
int *p = array; // p是一个指向int的指针变量,p = array合法
p[3]; // 等价于array[3]
void test(int a){ cout << "a=" << a << endl;} // test是一个函数指针常量,输入参数int,返回类型void
void (*pf)(int); // 声明函数指针pf: pf是一个输入参数int,返回void的函数的指针
pf = test; // 将test函数地址赋值给pf(二者输入参数列表、返回类型必须一致)
pf(123); // 等价于test(123)
有几点需要说明:
// 声明和赋值可以写在一起:
void (*pf)(int) = test;
// 2种赋值方式:(等价)
pf = test; // 直接函数名赋值
pf = &test; // 函数名取地址赋值,等价于pf = test
// 2种调用方式:(等价)
pf(123); // 直接pf接参数调用
(*pf)(123); // 先对函数指针解引用,再接参数调用,等价于pf(123)
例1:
#include <iostream>
using namespace std;
int add(int x, int y){
return x + y;
}
int substract(int x, int y){
return x - y;
}
int main(){
int (*fp)(int, int); // 定义函数指针变量:fp
fp = add; // 将同类型函数add赋值给fp
cout << fp(1, 3) << endl;
cout << (*fp)(1, 3) << endl; // 等价于fp(1,3)
fp = &substract; // 将同类型函数substract赋值给fp, 取地址符号"&"可加可不加
cout << fp(1, 3) << endl;
cout << (*fp)(1, 3) << endl; // 等价于fp(1,3)
return 0;
}
输出:
4
4
-2
-2
重载的函数自动匹配类型
如果有同名的重载函数,编译器会自动选择类型匹配的一个:#include <iostream>
using namespace std;
int add(int x, int y){
return x + y;
}
int add(int x, int y, int z){ // 重载
return x + y + z;
}
int main(){
int (*fp)(int, int) = add; // 编译器会自动选择add(int x, int y)与fp匹配
cout << "1 + 2 = " << fp(1,2) << endl;
int (*fp2)(int, int, int) = add; // 编译器会自动选择add(int x, int y, int z)与fp2匹配
cout << "1 + 2 + 3 = " << fp2(1,2,3) << endl;
return 0;
}
输出:
1 + 2 = 3
1 + 2 + 3 = 6
类型复杂的函数指针和typedef的妙用
当一个函数的输入列表、返回列表较为复杂时,尤其是参数/返回值中还嵌套了函数指针时,代码的可读性将会大大下降。1、输入参数包含函数指针
函数指针作为输入参数(形参)有两种写法:将输入参数int变为int (*pf)(int, int),表示输入参数为函数指针pf(指向函数类型为int (*pf)(int, int))。- void test(int fun(int, int)) // 直接把fun函数的声明写在参数的位置,在test内部fun作为形参变量,表示函数指针
- void test(int (*pf)(int, int)) // 将函数指针的声明写在参数的位置,在test内部pf作为形参变量,与上面写法等价
#include <iostream>
using namespace std;
int add(int x, int y){ // 双参数函数add2:两个数相加
return x + y;
}
int add2(int (*fun)(int, int), int x, int y, int z){ // 使用函数声明语句作为形参,构造三参数函数add2()
return fun(fun(x,y),z);
}
int add3(int fun(int, int), int x, int y, int z){ // 与上面等价, 使用函数指针作为形参,构造三参数函数add3()
return fun(fun(x,y),z);
}
int main(){
int (*fp)(int, int);
fp = add;
cout << "1 + 2 = " << fp(1,2) << endl;
int (*fp2)(int (*fun)(int, int), int, int, int); // 第一个参数是双参数函数指针,第二到四个参数为int
fp2 = add2; // fp2赋值为类型一致的函数名
cout << "1 + 2 + 3 = " << fp2(fp,1,2,3) << endl;
fp2 = add3; // 与上面等价,add3和add2实际是一样的,都能被fp2接收
cout << "4 + 5 + 6 = " << fp2(fp,4,5,6) << endl;
return 0;
}
输出结果:
1 + 2 = 3
1 + 2 + 3 = 6
4 + 5 + 6 = 15
2、返回值为函数指针
函数指针作为返回值的写法:只需要将int fun(int)变成 int (*fun(int))(double, double), 表示fun(int)返回一个函数指针pf(指向类型为int (*pf)(double, double))。- int (*createAdd())(int, int); // 定义一个名为createAdd()的函数,输入参数为空,返回值为一个函数指针pTemp(其类型为int (pTemp)(int, int))
- int (*createAlgorithm(int type))(int, int); // 定义一个名为createAlgorithm(int)的函数:输入参数为int,返回值为对应运算符的函数指针pTemp(其类型为int (*pTemp)(int, int))
#include <iostream>
using namespace std;
int add(int x, int y){
return x + y;
}
// 定义一个名为createAdd()的函数
// 输入参数为空
// 返回值为一个函数指针pTemp(其类型为int (*pTemp)(int, int))
int (*createAdd())(int, int){
return add;
}
int main(){
int (*fp)(int, int); // 声明一个函数指针fp
fp = createAdd(); // fp接收createAdd()返回值,二者都是同类型的函数指针,匹配
cout << "1 + 2 = " << fp(1,2) << endl;
return 0;
}
输出:
1 + 2 = 3
例4:带参数输入的createAlgorithm(int type)函数返回一个函数指针:
#include <iostream>
using namespace std;
// 定义三种运算:空运算、加法、减法
int none(int , int ){
return 0;
}
int add(int x, int y){
return x + y;
}
int substract(int x, int y){
return x - y;
}
// 定义一个名为createAlgorithm(int)的函数:
// 输入参数为int,表示选择哪一种运算符(1为加法,2为减法)
// 返回值为对应运算符的函数指针pTemp(其类型为int (*pTemp)(int, int))
int (*createAlgorithm(int type))(int, int){
switch(type){
case 1:
return add;
break;
case 2:
return substract;
break;
default:
return none;
}
}
int main(){
int (*fp)(int, int); // 声明一个函数指针fp
fp = createAlgorithm(1); // fp接收createAlgorithm(1)返回值,二者都是同类型的函数指针,匹配
cout << "1 + 2 = " << fp(1,2) << endl;
fp = createAlgorithm(2); // fp接收createAlgorithm(2)返回值,二者都是同类型的函数指针,匹配
cout << "5 - 1 = " << fp(5,1) << endl;
return 0;
}
输出:
1 + 2 = 3
5 - 1 = 4
例5:输入参数和返回参数都含有函数指针:(int (calculateAndTransfer(int (fun)(int, int), int x, int y))(int, int){...})
#include <iostream>
using namespace std;
int add(int x, int y){
return x + y;
}
int substract(int x, int y){
return x - y;
}
// 定义一个名为calculateAndTransfer(int)的函数:在内部执行一次计算,并且把输入的函数指针再返回,传递下去
// 输入参数为函数指针(其类型为int (*pTemp)(int, int))和两个int变量
// 返回值为同样的函数指针pTemp(其类型为int (*pTemp)(int, int))
int (*calculateAndTransfer(int (*fun)(int, int), int x, int y))(int, int){
cout << "fun(x,y) = " << fun(x,y) << endl;
return fun;
}
int main(){
int (*fp)(int, int);
fp = calculateAndTransfer(add,1,2);
cout << "1 + 2 = " << fp(1,2) << endl;
fp = calculateAndTransfer(substract,5,1);
cout << "5 - 1 = " << fp(5,1) << endl;
return 0;
}
输出:
fun(x,y) = 3
1 + 2 = 3
fun(x,y) = 4
5 - 1 = 4
可见,当函数指针出现在输入参数或者返回值位置时,代码可读性将会大大下降,这不利于项目的开发和维护。
3、typedef提高代码可读性
3.1 typedef自定义类型别名
通过上面的例子发现,当函数输入参数或者返回值包含函数指针时,代码可读性将会大大降低。为了解决这个问题,C++中可以使用typedef预先给某一类型起别名,然后再用自定义的别名会写出更让人容易理解的代码。函数/函数指针使用typedef的两种方式:
- typedef int Fun(int, int); // 类型别名:Fun代表一类函数
- **typedef int (PFun)(int, int); ** // 类型别名
Fun代表一类函数指针 (int (pf)(int, int))
3.2 用typedef重写:函数指针作为输入参数
例6、用typedef重写:函数指针作为输入参数:#include <iostream>
using namespace std;
typedef int Fun(int, int); // 类型别名:Fun代表一类函数
typedef int (*PFun)(int, int); // 类型别名
Fun代表一类函数指针int add(int x, int y){ // 双参数函数add2:两个数相加
return x + y;
}
int add2(int (*fun)(int, int), int x, int y, int z){ // 利用双参数输入的fun(), 构造三参数函数add2()
return fun(fun(x,y),z);
}
int add4(PFun fun, int x, int y, int z){ // 与add2等价, 利用typedef提高可读性,构造三参数函数add3()
return fun(fun(x,y),z);
}
int add5(Fun fun, int x, int y, int z){ // 与add4等价, 函数名会被自动转换为函数指针作为形参
return fun(fun(x,y),z);
}
int main(){
// 函数指针直接使用:
int (*fp)(int, int);
fp = add;
cout << "1 + 2 = " << fp(1,2) << endl;
// 同上,但使用typedef提高可读性
PFun fp2 = add; // 与fp是同一类型
cout << "1 + 2 = " << fp2(1,2) << endl;
// 函数指针作为输入参数(形参)时,使用typedef的add4和add5的代码可读性比add2更高:
cout << "1 + 2 + 3 = " << add2(fp2, 1, 2, 3) << endl;
cout << "1 + 2 + 3 = " << add4(fp2, 1, 2, 3) << endl;
cout << "1 + 2 + 3 = " << add5(fp2, 1, 2, 3) << endl;
return 0;
}