函数指针,就是指向函数的指针。在C++中,函数指针一般是指全局命名空间中的函数指针,它与类成员函数指针有一点不同。
在类中,首先类是具有类域的。一个指向类的成员函数的指针,不同于函数指针,只是声明的形式不同,基本思想还是一致的。使用这些指针对操作可能会带来很大的方便。
另外,对于静态类来说,静态类没有this指针,静态类成员函数指针是普通函数指针,因为静态类成员函数是属于类的全局函数。
函数指针
先看一下函数指针的定义及其使用。
函数指针的定义需要指明函数返回类型、函数参数列表,这样才能使一个函数指针指向正确的函数,例如,定义一个返回值为void、没有参数列表的函数指针变量function_pointer,并对其初始化,初始化内容是函数void set_student_count():
void (*function_pointer)() = set_student_count;
如果另一个函数void set_car_number()也是返回值为void、参数列表为空,可将该函数初始化给函数指针变量function_pointer,如下所示:
function_pointer = set_car_number;
函数的参数列表不为空的话,也是一样的,要在声明一个函数指针的时候指明包含的函数参数列表内容(参数类型),例如,函数返回类型为void、参数列表为(string& , int),比如函数void get_from_first(string& s, int count) ,指向该函数的指针变量my_function_pointer可以声明并初始化为:
void (*my_function_pointer)(string& , int) = get_from_first;
对于函数参数列表很长的函数,如果声明一个函数指针类型变量,显得很长,可以使用typedef来重定义函数指针类型,例如对上面的函数指针类型变量void (*my_function_pointer)(string& , int),可以重定义为:
typedef void (*FP)(string&, int);
这里,FP就是指向返回类型为void、参数列表为(string& , int)的函数指针类型。接着,定义一个函数指针类型的变量,并初始化其值为函数get_from_first,如下所示:
FP fp = get_from_first;
下面,写了两个函数get_from_first与get_from_last,分别从一个字符串的头部、尾部截取指定长度的字符串。通过定义函数指针FP指向这两个函数,将几个这两个函数的指针变量放入到容器vector中,然后迭代vector,使用迭代出来的函数对一个初始字符串进行操作。
代码实现如下所示:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
typedef void (*FP)(string&, int); // 重定义函数指针类型
void print_message(int, const char*, string&);
inline void get_from_first(string& s, int count) { s = s.substr(0, count); }
inline void get_from_last(string& s, int count) { s = s.substr(s.size()-count); }
void print(int count, FP fp, string& after_s) {
if(fp == get_from_first) {
print_message(count, "get_from_first", after_s);
}
if(fp == get_from_last) {
print_message(count, "get_from_last", after_s);
}
}
void print_message(int count, const char *fname, string& after_s) {
cout<<"Recall function "<<fname<<"\t[count="<<count<<"]\t:\t"<<after_s<<endl;
}
int main() {
string s = "abcedfghijklmnopqrstuvwxyz9876543210";
vector<FP> fp_vector;
FP pf1 = get_from_first;
fp_vector.push_back(pf1);
FP pf2 = get_from_first;
fp_vector.push_back(pf2);
FP pl1 = get_from_last;
fp_vector.push_back(pl1);
FP pl2 = get_from_last;
fp_vector.push_back(pl2);
FP pl3 = get_from_last;
fp_vector.push_back(pl3);
int count_array[] = { 30, 25, 15, 8, 1 };
for(int i=0; i<5; i++) {
FP fp = fp_vector.at(i);
fp(s, count_array[i]);
print(count_array[i], fp, s);
}
return 0;
}
编译运行,结果如下所示:
Recall function get_from_first [count=30] : abcedfghijklmnopqrstuvwxyz9876
Recall function get_from_first [count=25] : abcedfghijklmnopqrstuvwxy
Recall function get_from_last [count=15] : klmnopqrstuvwxy
Recall function get_from_last [count=8] : rstuvwxy
Recall function get_from_last [count=1] : y
类成员函数指针
类成员函数指针,与函数指针不同的是,类具有类域操作符,在声明类成员函数指针的时候,要指定成员函数返回值类型、类域操作符、成员函数参数列表,例如,对于一个已经存在的类TruncateString来说,它有成员函数void get_from_first(string& s, int count);,声明指向类TruncateString的成员函数指针,可以声明并初始化为如下形式:
void (TruncateString::*tsfpf)(string&, int) = &TruncateString::get_from_first;
其中, void (TruncateString::*tsfpf)(string&, int)是声明指向TruncateString类成员函数,tsfpf是一个指向TruncateString类成员函数的指针变量,初始化的值&TruncateString::get_from_first表示是类TruncateString的成员函数void get_from_first(string& s, int count)。
说明一点,如何取得一个类成员函数指针变量的值的问题,也就是以怎样的形式为一个类的成员函数指针变量赋值,或者要进行比较,需要使用“引用操作符&、类域作用符、类成员函数”顺序连接的方式来获取到,例如上面例子中的&TruncateString::get_from_first,其中第三个部分只需要指定类成员函数的名称即可,不需要指明类成员函数的参数列表。
可以看出,“指向TruncateString类成员函数指针类型”这个类型很长,可以使用typedef重新定义类型,如下所示:
typedef void (TruncateString::*TSFP)(string&, int);
上面的TSFP,就是指向TruncateString类成员函数指针类型,它等价于上面的void (TruncateString::*)(string&, int),直接使用TSFP就能方便地声明指向TruncateString类成员函数的指针变量。
下面,将前面基于过程的函数指针的例子,转换成一个类TruncateString,从而方便灵活地使用类成员函数指针,TruncateString类定义在TruncateString.h头文件中,如下所示:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class TruncateString;
typedef void (TruncateString::*TSFP)(string&, int); // 重定义指向该类的成员函数的指针类型
class TruncateString {
public:
inline void get_from_first(string& s, int count) { s = s.substr(0, count); }
inline void get_from_last(string& s, int count) { s = s.substr(s.size()-count); }
void print(int count, const TSFP tsfp, string& after_s);
private:
void print_message(int count, const char *fname, string& after_s);
};
TruncateString类中没有定义数据成员。接着,TruncateString类的成员函数实现在TruncateString.cpp文件中,如下所示:
#include "TruncateString.h"
void TruncateString::print(int count, const TSFP tsfp, string& after_s) {
if(tsfp == &TruncateString::get_from_first) {
print_message(count, "TruncateString::get_from_first", after_s);
}
if(tsfp == &TruncateString::get_from_last) {
print_message(count, "TruncateString::get_from_last", after_s);
}
}
void TruncateString::print_message(int count, const char *fname, string& after_s) {
cout<<"Recall function "<<fname<<"\t[count="<<count<<"]\t:\t"<<after_s<<endl;
}
类TruncateString的实现中,通过成员函数指针变量调用成员函数执行,在这里实现了对调用成员函数执行情况进行打印输出信息的,因为在TruncateString类的头文件TruncateString.h中定义并实现了内联成员函数:inline void get_from_first(string& s, int count)与inline void get_from_last(string& s, int count)。
比较关键而且重要的是,如果调用类成员函数指针所指向的成员函数,通过实现一个测试用例类TruncateStringTest.cpp,来学习如何使用类成员函数指针变量:
#include <vector>
#include "TruncateString.h"
int main() {
string s = "abcedfghijklmnopqrstuvwxyz9876543210";
TruncateString *pts = new TruncateString;
vector<TSFP> tsfp_vector;
TSFP tsfpf1 = &TruncateString::get_from_first;
tsfp_vector.push_back(tsfpf1);
TSFP tsfpf2 = &TruncateString::get_from_first;
tsfp_vector.push_back(tsfpf2);
TSFP tsfpl1 = &TruncateString::get_from_last;
tsfp_vector.push_back(tsfpl1);
TSFP tsfpl2 = &TruncateString::get_from_last;
tsfp_vector.push_back(tsfpl2);
TSFP tsfpl3 = &TruncateString::get_from_last;
tsfp_vector.push_back(tsfpl3);
int count_array[] = { 30, 25, 15, 8, 1 };
for(int i=0; i<5; i++) {
TSFP tsfp = tsfp_vector.at(i);
(pts->*tsfp)(s, count_array[i]);
pts->print(count_array[i], tsfp, s);
}
delete pts;
return 0;
}
上面对字符串"abcedfghijklmnopqrstuvwxyz9876543210",通过类TruncateString的提供的操作来处理。同样,定义了使用vector<TSFP>容器来存放指向TruncateString类的成员函数指针变量,从而迭代vector<TSFP>容器,连续使用vector<TSFP>容器中的类成员方法,对给定的字符串进行处理。
因为声明TruncateString *pts类指针变量,所以从vector<TSFP>容器中迭代出一个TSFP变量后,需要按照如下方式,将数据传入,调用成员函数处理:
(pts->*tsfp)(s, count_array[i]);
其实,很好理解,根据括号“()”内的运算顺序,首先从左侧:通过*tsfp获取类的成员函数,再通过类指针变量pts通过指针运算符“->”来调用成员函数*tsfp,接着后面的括号中指定实参,就能够运算了。
如果定义一个类的变量:
TruncateString ts;
实现上述功能的等价调用形式如下所示:
(pts.*sfp)(s, count_array[i]);
就是将指针运算符“->”改成了“.”运算符,容易理解。
对测试用例类进行编译,运行输出测试结果如下所示:
[root@bogon pointer]# g++ -o TruncateString Trun*.cpp
[root@bogon pointer]# ./TruncateString
Recall function TruncateString::get_from_first [count=30] : abcedfghijklmnopqrstuvwxyz9876
Recall function TruncateString::get_from_first [count=25] : abcedfghijklmnopqrstuvwxy
Recall function TruncateString::get_from_last [count=15] : klmnopqrstuvwxy
Recall function TruncateString::get_from_last [count=8] : rstuvwxy
Recall function TruncateString::get_from_last [count=1] : y
可见,同前面的函数指针中的测试程序的功能是相同的。
静态类的静态成员函数指针
静态类静态成员函数指针与普通函数指针的声明是相同的,不同的对于静态类的静态成员函数指针变量进行赋值时,应该在静态类的静态成员函数名称前面加上静态类类域作用符。
例如TruncateString是一个静态类,它有一个静态成员函数static void get_from_last(string& s, int count);,那么,声明指向静态类TruncateString的静态成员函数指针变量,并进行初始化,形式如下:
void (*static_tspf)(string&, int) = &TruncateString::get_from_last;
其中static_tspf就是指向静态类TruncateString的静态成员函数的指针变量。使用指向静态类静态成员函数指针变量,对应于上面使用的例子,调用方式形如:
tsfp(s, count_array[i]); // tsfp是指向静态类TruncateString的静态成员函数的指针变量
TruncateString::print(count_array[i], tsfp, s); // 通过类域作用符调用静态类的静态成员函数
其实,在了解了函数指针和非静态类成员函数指针以后,对于静态类的成员函数指针变量的使用,应该很容易就能理解。