免费 C++函数指针详解(下)

  • 主题发起人 主题发起人 Scare
  • 开始时间 开始时间

Scare

0xFF|主权幽灵
07
908
172
奇源币
0
管理成员
工作人员
版主
VIP

3.3 用typedef重写:函数指针作为返回值:​

以下两者为等价写法:都是定义一个名为createAlgorithm(int)的函数,输入参数为int,返回值为函数指针pTemp(其类型为int (*pTemp)(int, int))

  • int (createAlgorithm(int type))(int, int){ ...} // 不使用typedef,返回类型写法难以阅读
  • typedef int (*PFun)(int, int);
    PFun createAlgorithm(int type){ ... } // 可见,用typedef定义的类型PFun写法同一般的返回类型写法,更容易理解
例7:用typedef重写:函数指针作为返回值:

#include <iostream>
using namespace std;

// PFun是一个函数指针的类型别名,指向函数的类型为int (*pTemp)(int, int)
typedef int (*PFun)(int, int);

// 定义三种运算:空运算、加法、减法
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){ xxx }
PFun createAlgorithm(int type){
switch(type){
case 1:
return add;
break;
case 2:
return substract;
break;
default:
return none;
}
}

int main(){
PFun 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

注:类型别名除了typedef之外,还有using和decltype,都可以实现函数指针的别名定义。例如下面三条语句定义的PFun1, PFun2, PFun3等价。

例8:typedef、using和decltype三种等价写法:

#include <iostream>
using namespace std;

int add(int x, int y){
return x + y;
}

// 以下为类型别名的三种等价写法:
typedef int (*PFun1)(int, int); // 类型别名:PFun1代表一类函数指针
using PFun2 = int (*)(int, int); // 类型别名:PFun2与PFun1等价
typedef decltype(add) *PFun3; // 类型别名:PFun3与PFun1等价

int main(){
PFun1 fp1 = add;
PFun2 fp2 = add;
PFun3 fp3 = fp2;
cout << "1 + 2 = " << fp1(1,2) << endl;
cout << "1 + 2 = " << fp2(1,2) << endl;
cout << "1 + 2 = " << fp3(1,2) << endl;
return 0;
}

输出:

1 + 2 = 3
1 + 2 = 3
1 + 2 = 3

3.4 用typedef重写:输入参数和返回参数都含有函数指针:以下两种写法等价:​

  • int (*calculateAndTransfer(int (*fun)(int, int), int x, int y))(int, int)
  • typedef int (*PFun)(int, int);
    PFun calculateAndTransfer(PFun fun, int x, int y); // typedef大大提高可读性
例9:用typedef重写例5,让代码具有更好的可读性:

#include <iostream>
using namespace std;

typedef int (*PFun)(int, int);

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){
PFun calculateAndTransfer(PFun fun, int x, int y){
cout << "fun(x,y) = " << fun(x,y) << endl;
return add;
}

int main(){
PFun fp;
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 = 6

函数指针的数组​

定义一个由函数指针组成的数组:([]的优先级高于*,因此直接把(*fp)变为(*fp[3])即可

  • int (*fp[3])(int, int) : fp是一个数组,元素个数为3,每个元素是一个函数指针(指向int (*pf)(int, int)的类型)
  • int (*(fp[3])(int, int) : 与上面等价,fp是一个数组
  • int ((*fp)[3])(int, int) : (非法,编译会报错:```error: declaration of 'gp' as array of functions):fp是一个指针,指向一个数组,这个数组的元素个数必须为3,每个元素是一个函数,注意,是函数而不是函数指针,*符号给到fp头上了,因此,编译器会认为你要创建函数的数组,这是不允许的,只允许创建函数指针的数组。
例10:函数指针数组:

#include <iostream>
using namespace std;

typedef int (*PFun)(int, int);

int add(int x, int y){
return x + y;
}

int substract(int x, int y){
return x - y;
}

int main(){
// fp是一个数组,元素个数为2,每个元素是一个函数指针(指向int (*pf)(int, int)的类型)
int (*fp[2])(int, int);
fp[0] = add;
fp[1] = substract;
cout << fp[0](5,3) << endl;
cout << fp[1](5,3) << endl;

// 下面会报错,从字面上理解:gp是一个指针,指向函数的数组,而函数的数组是非法的,函数指针的数组是允许的
// int ((*gp)[2])(int, int); \\ error: declaration of 'gp' as array of functions

return 0;
}

输出:

8
2

类的成员函数(方法)的指针​

与普通函数指针类似,类的静态/非静态成员函数(方法)指针也有声明、赋值、调用三个步骤:

普通函数类的非静态成员函数
(类名为A,实例对象为a,对象指针为pa)
类的静态成员函数(类名为A)
函数声明int fun(double x, double y);int A::fun(double x, double y);int A::static_fun(double, double);
函数指针的声明int (*fp)(double, double);int (A::*fp2)(double x, double y);int (*fp3)(double, double);
函数指针的赋值fp = fun; 或 fp = &fun;fp2 = A::fun;或 fp2 = &A::fun;fp3 = A::static_fun;
函数指针的调用fp(x, y); 或 (*fp)(x, y);(a.*fp2)(x,y);
(pa->*fp2)(x,y);
fp3(x, y); 或 (*fp3)(x, y);
几个注意点:

  • 新引入三个运算符:声明::*, 调用.*和->*。
  • 声明时,只有类的非静态成员函数指针前才加类名。
  • 赋值时,函数指针前都不加类名,只有类的非静态成员函数指针的等号右侧的才加类名。
  • 调用时,只有类的非成员函数指针前要加对象名,因为必须通过this指针来决定调用的是哪个实例对象的函数。其中(a.*fp2)(x,y)和(pa->*fp2)(x,y)的小括号不能省略,因为.*和->*的优先级低于()。
总之,类的静态成员函数与普通函数非常类似,只有在赋值的时候需要等号右侧是类名::静态函数的形式,其他的语法完全一致。而类的非静态成员函数在声明时前面要加类名,赋值时等号右侧要加类名,调用时前面要加具体的对象名。

例11:比较普通函数、类的非静态成员函数、类的静态成员函数的声明、赋值和调用:

#include <iostream>
#include <string>
using namespace std;

class Mobile{
public:
Mobile(string number):_number(number){}
void from(string another_number){
cout << _number << " is receiving a call from " << another_number << endl;
}
void to(string another_number){
cout << _number << " is calling to " << another_number << endl;
}
static void printInfo(){
cout << "Static function: Mobile works good!" << endl;
}
private:
string _number;
};

void fun(string number){
cout << "Normal function: number " << number << endl;
}

int main(){
// 普通函数的指针:
void (*fp1)(string); // 声明
fp1 = fun; // 赋值
fp1("999"); // 调用
(*fp1)("999"); // 调用的第二种等价方式

// 类的非静态成员函数(方法)的指针:
Mobile m("666888"), *mp = &m;
void (Mobile::*fp2)(string); // 声明,使用 ::* (小括号不能少:写成Mobile::*fp2(string)会报错)
fp2 = Mobile::from; // 赋值,也可以写成fp2 = &Mobile::from; 因为::优先级高于&
(m.*fp2)("12345"); // 调用,不能写成 m.*fp2("12345") 因为.*的优先级低于()
// (*(m.*fp2))("12345"); // 错误,调用没有像普通函数一样的第二种等价方式(前面加*)
(mp->*fp2)("12345"); // 调用,不能写成 m->*fp2("12345") 因为->*的优先级低于()
fp2 = Mobile::to; // 赋值
(m.*fp2)("54321"); // 调用
(mp->*fp2)("54321"); // 调用

// 类的静态成员函数(方法)的指针:
void (*fp3)(); // 声明: 同普通函数
fp3 = Mobile::printInfo; // 赋值:等号右侧用类名::静态函数,也可以写成fp3 = &Mobile::printInfo;
fp3(); // 调用:同普通函数
(*fp3)(); // 调用的第二种等价方式:同普通函数

return 0;
}

输出:

Normal function: number 999
Normal function: number 999
666888 is receiving a call from 12345
666888 is receiving a call from 12345
666888 is calling to 54321
666888 is calling to 54321
Static function: Mobile works good!
Static function: Mobile works good!
 
后退
顶部