C++手稿:STL中的函数对象与函数指针
STL是C++的标准模板库(standard template library),自然其中定义的都是模板。 相比于类和函数声明的显式接口(explicit interface),类模板和函数模板声明的接口属于隐式接口(implicit interface)。 因为模板参数应当满足的接口是由模板中表达式的合法性决定的,这一点给了模板很大的自由。 而函数对象和函数指针具有同样的调用语法,因此STL中这两者常常可以互换。
更多关于隐式接口和显式接口的概念和区别,参见Effective C++: Item 41。
先来感受一下C++中的函数对象和函数指针:
template<typename T>
void printer(int a, int b, T func){
cout<<func(a, b)<<endl;
}
在STL中定义了很多像上面这样的模板,这里的T是一个可调用(实现了括号运算符)的东西。 这使得我们在使用模板时可以指定一个计算策略,它可以是函数对象,也可以是函数指针。
Less<int>
便是一个常见的函数对象,常用来配置容器或算法。<functional>
中定义了很多这样的函数对象。
函数指针
函数指针通常用来将函数传参或存储。例如:
int sum(int a, int b){
return a+b;
}
int main(){
printer(2, 3, sum);
return 0;
}
上述的printer
调用方式,编译器会生成对应的函数实例:
void printer(int a, int b, int (*func)(int, int)){
cout<<func(a, b)<<endl;
}
这里T
的类型是int (*)(int, int)
。
如果你是python或者javascript程序员的话,上述过程没有什么特别的。 唯一要注意的是
func
的声明方式,星号要和标识符括起来:(*func)
。
函数对象
函数对象是重载了括号运算符的类的实例,它也可以这样调用:func(a, b)
。例如:
class Sum{
public:
int operator()(int a, int b){
return a+b;
}
};
int main(){
printer(2, 3, Sum());
return 0;
}
编译器会生成这样的函数实例:
void printer(int a, int b, Sum s){
cout<<s(a, b)<<endl;
}
函数对象可以实现更加复杂的有状态的运算,因为对象可以有更多的属性和方法。