-
函数指针作为传入参数:
C++中函数名的本质为指向函数的指针,可以被传递到接受方法指针作为参数的函数中去,这在不少STL算法函数的可选参数中有所体现。
以常用的一个算法函数binary_search为例,在C++ reference中,可以查得它的两个传入参数分别如下:
template< class ForwardIt, class T >bool binary_search( ForwardIt first, ForwardIt last, const T& value );template< class ForwardIt, class T, class Compare >bool binary_search( ForwardIt first, ForwardIt last, const T& value, Compare comp );
这说明binary_search这个函数除了接受两个迭代和一个参数作为传入参数之外,还可以接受comp作为参数,其有两个重载了同一个函数名的函数。因此,如果在一个正序以及倒序排序的序列中查找某个元素,就分别要用到这两个不同版本的重载函数,代码的示例如下:
#include#include #include #include using namespace std;bool compare(int num1, int num2){ return num1 > num2; }int main(int argc, char** argv) { vector intV1 = {1, 3, 5, 7, 9}; vector intV2 = {9, 7, 5, 3, 1}; //Searching in ascending order: bool is5Exist = binary_search(intV1.cbegin(), intV1.cend(), 5); cout << "Element 5 " << (is5Exist ? "exsits" : "does not exist") << " in int vector 1. " << endl; //Searching in descending order, need to specify the descending order: is5Exist = binary_search(intV2.cbegin(), intV2.cend(), 5, compare); cout << "Element 5 " << (is5Exist ? "exsits" : "does not exist") << " in int vector 2. " << endl; return 0;}
上述代码中,compare就作为函数指针在对第二个vector进行搜索时作为传入参数。然而,除了函数指针能够作为传入参数,函数对象作为指针对应的地址,也能参与传入。此外,lambda表达式也可传入。本文重点介绍函数对象的传入机制。
-
用户定义的函数对象作为传入参数:
由于指针事实上对应地址,因此Compare参数接受的参数还可以是类或者结构体。举例如下:
class CompareEle{public: bool operator()(int num1, int num2){ return num1 > num2;}};struct CompareNum{ bool operator()(int num1, int num2){ return num1 > num2;}};
对于上述类和结构体的调用大体是相同的,举例如下:
//调用用类声明的比较:is5Exist = binary_search(intV2.cbegin(), intV2.cend(), 5, CompareEle());//调用用结构体声明的比较:is5Exist = binary_search(intV2.cbegin(), intV2.cend(), 5, CompareNum());
此处,在类或者结构体中重写了方法调用函数,即bool operator(),即定义了用户定义的比较不同元素之间的方式。
-
STL自带函数对象作为传入参数:
由上述例子可见,函数对象的应用还是非常广泛的。考虑到这点,C++的标准模版库中已经储备了一些常用的函数对象,如下面例子中的std::greater。更多这样的函数对象,详情可以参见参考资料3。因此,上述在第二个vector中搜索元素5的调用还可以书写如下:
is5Exist = binary_search(intV2.cbegin(), intV2.cend(), 5, std::greater ());
-
总结比较:
本文简单介绍了C++函数指针、函数对象的概念以及函数指针和函数对象在标准模版库中的几种使用方式。由于C++的编译器通常能对函数对象(也即类或结构体书写的重载方法调用函数)作出优化,因此更加推荐在编程中使用函数对象或者C++ STL自带的函数对象声明对象之间的关系。此外,自定义的函数指针和函数对象返回值也不仅仅限于bool,还可以是其他形式。比如参考资料4的第554页就给出了如下例子:
#include#include #include #include #include // array class-template definition#include // copy algorithm#include // accumulate algorithm#include // binary_function definition#include // ostream_iteratorusing namespace std;// binary function adds square of its second argument and the// running total in its first argument, then returns the sum int sumSquares( int total, int value ) { return total + value * value; } // end function sumSquares// Class template SumSquaresClass defines overloaded operator()// that adds the square of its second argument and running // total in its first argument, then returns sum template< typename T > class SumSquaresClass {public: // add square of value to total and return result T operator()( const T &total, const T &value ) { return total + value * value; } // end function operator()}; // end class SumSquaresClassint main(){ const size_t SIZE = 10; array< int, SIZE > integers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; ostream_iterator< int > output( cout, " " ); cout << "array integers contains:\n"; copy( integers.cbegin(), integers.cend(), output ); // calculate sum of squares of elements of array integers // using binary function sumSquares int result = accumulate( integers.cbegin(), integers.cend(), 0, sumSquares ); cout << "\n\nSum of squares of elements in integers using " << "binary\nfunction sumSquares: " << result; // calculate sum of squares of elements of array integers // using binary function object result = accumulate( integers.cbegin(), integers.cend(), 0, SumSquaresClass< int >() ); cout << "\n\nSum of squares of elements in integers using " << "binary\nfunction object of type " << "SumSquaresClass< int >: " << result << endl;} // end main
此处,用户定义的函数指针和函数对象返回值分别为int和T,定义了计算求和的方式,这种用法值得参考学习。
参考资料:
- binary_search的使用参考,URL:
- chengyang的博客,URL:
- 函数对象参考资料,URL:
- Paul Deitel & Harvey Deitel, 《C++11程序设计(英文版)(第2版)》,2016年4月,电子工业出版社