前言
在之前写过的博客中有介绍过函数指针和指针函数的区别和简单用法(文章在这里),当时的Demo非常简单,都是C语言的写法,但是当在C++中直接像C那样使用类成员函数指针时就会报错:reference to non-static member function must be called
所以如果是C++中的成员函数指针其使用方法是有区别的,这里针对不同的场景做个补充说明。
类成员函数的指针(非静态)
指向类成员函数的指针与普通函数指针的区别在于,前者需要匹配函数的参数类型和个数以及返回值类型,还要匹配该函数指针所属的类类型。
这是因为非静态的成员函数必须被绑定到一个类的对象或者指针上,才能得到被调用对象的this指针,然后才能调用指针所指的成员函数(所有类的对象都有自己数据成员的拷贝,但是成员函数都是共用的,为了区分是谁调用了成员函数,就必须有this指针,this指针是隐式的添加到函数参数列表里去的)。
所以,对于类成员函数的指针使用包含以下几个步骤:
声明: 指向类的成员函数的指针需要在指针前面加上类的类型,格式为:
typedef 返回值 (类名::*指针类型名)(参数列表);
赋值: 需要用类的成员函数地址赋值,格式为:
指针类型名 指针名 = &类名::成员函数名;
注意:这里的这个&符号是比较重要的:不加&,编译器会认为是在这里调用成员函数,所以需要给出参数列表,否则会报错;加了&,才认为是要获取函数指针。这是C++专门做了区别对待。
调用: 针对调用的对象是对象还是指针,分别用.*和->*进行调用,格式为:
(类对象.*指针名)(参数列表);
(类指针->*指针名)(参数列表);
注意:这里的前面一对括号是很重要的,因为()的优先级高于成员操作符指针的优先级。
直接来看一个示例吧:
class Calculation
{
public:
int add(int a,int b){ //非静态函数
return a + b;
}
};
typedef int (Calculation::*FuncCal)(int,int);
int main()
{
FuncCal funAdd = &Calculation::add;
Calculation * calPtr = new Calculation;
int ret = (calPtr->*funAdd)(1,2); //通过指针调用
Calculation cal;
int ret2 = (cal.*funAdd)(3,4); //通过对象调用
cout << "ret = " << ret << endl;
cout << "ret2 = " << ret2 << endl;
return 0;
}
指向类的静态函数的指针
类的静态成员函数和普通函数的函数指针的区别在于,他们是不依赖于具体对象的,所有实例化的对象都共享同一个静态成员,所以静态成员也没有this指针的概念。
所以,指向类的静态成员的指针就是普通的指针。
class Calculation
{
public:
static int add(int a,int b){ //非静态函数
return a + b;
}
};
typedef int (*FuncCal)(int,int);
int main()
{
FuncCal funAdd = &Calculation::add;
int ret = (*funAdd)(1,2); //直接引用
int ret2 = funAdd(3,4); //直接引用
cout << "ret = " << ret << endl;
cout << "ret2 = " << ret2 << endl;
return 0;
}
总结以上两种情况的区别:
- 如果是类的静态成员函数,那么使用函数指针和普通函数指针没区别,使用方法一样
- 如果是类的非静态成员函数,那么使用函数指针需要加一个类限制一下。
使用函数指针,很多情况下是用在函数的参数中,在一些复杂的计算,如果需要重复调用,并且每次调用的函数不一样,那么这时候使用函数指针就很方便了,可以减少代码量。
参考资料:
https://blog.csdn.net/houzijushi/article/details/81503409
https://www.cnblogs.com/lvchaoshun/p/7806248.html
https://www.cnblogs.com/AnnieKim/archive/2011/12/04/2275589.html