一起来学习C++的函数指针和函数对象
目录
- 函数指针
- 函数对象
- 总结
函数指针 以下是
void qsort (void* base, size_t num, size_t size,int (*compar)(const void*, const void*));
base
-- 指向要排序的数组的第一个元素的指针。num
-- 由 base 指向的数组中元素的个数。size
-- 数组中每个元素的大小,以字节为单位。compar
-- 用来比较两个元素的函数。
int compareMyType (const void * a, const void * b) {if ( *(MyType*)a <*(MyType*)b ) return -1; if ( *(MyType*)a == *(MyType*)b ) return 0; if ( *(MyType*)a >*(MyType*)b ) return 1; }
#include#include int cmpfunc (const void* a, const void* b); using namespace std; int main() { int values[] = { 88, 56, 100, 2, 25 }; qsort(values, sizeof(values)/sizeof(int), sizeof(int), cmpfunc); cout << "排序之后的列表:" << endl; for(int n = 0 ; n < 5; n++ ) {cout << values[n] << " "; } return 0; }int cmpfunc (const void* a, const void* b) { return ( *(int*)a - *(int*)b ); }
Enter a string (empty line to quit):|abcEnter menu choice:u) uppercase l) lowercaset) transposed case o) original casen) next stringPlease enter u, l, t, o, or n:|u ABCEnter menu choice:u) uppercase l) lowercaset) transposed case o) original casen) next stringPlease enter u, l, t, o, or n:|l abc
#include#include #include #include #include #define LEN 81char showmenu(); void show(void (* fp)(char*), char* str); void ToUpper(char*); // 把字符串转换为大写void ToLower(char*); // 把字符串转换为小写void Transpose(char*); // 大小写转置void Dummy(char*); // 不更改字符串using namespace std; int main() { char line[LEN]; char copy[LEN]; char choice; void (* pfun)(char*); // 声明一个函数指针, 被指向的函数接受char *类型的参数, 无返回值 cout << "Enter a string (empty line to quit):"; while (cin >> line) {while ((choice = showmenu()) != 'n') {switch (choice) { // switch语句设置指针case 'u':pfun = ToUpper; break; case 'l':pfun = ToLower; break; case 't':pfun = Transpose; break; case 'o':pfun = Dummy; break; }strcpy(copy, line); // 为show()函数拷贝一份show(pfun, copy); // 根据用户的选择, 使用选定的函数}cout << "Enter a string (empty line to quit):"; } cout << "Bye!"; return 0; } char showmenu() { char ans; cout << "Enter menu choice:" << endl; cout << "u) uppercase l) lowercase" << endl; cout << "t) transposed case o) original case" << endl; cout << "n) next string" << endl; ans = getchar(); // 获取用户的输入 ans = tolower(ans); // 转换为小写 while (strchr("ulton", ans) == NULL) {cout << "Please enter u, l, t, o, or n:" << endl; ans = tolower(getchar()); } return ans; }void show(void (* fp)(char*), char* str) { (*fp)(str); // 把用户选定的函数作用于str cout << str << endl; // 显示结果}void ToUpper(char* str) { while (*str) {*str = toupper(*str); str++; }}void ToLower(char* str) { while (*str) {*str = tolower(*str); str++; }}void Transpose(char* str) { while (*str) {if (islower(*str))*str = toupper(*str); else if (isupper(*str))*str = tolower(*str); str++; }}void Dummy(char* str) {} //不改变字符串
函数对象 函数对象是专门设计用于语法与函数相似的对象。在C++中,这是通过在类中定义成员函数
operator()
来实现的,例如:struct myclass { int operator()(int a) {return a; }} myobject; int x = myobject(0);
它们通常用作函数的参数,例如传递给标准算法的谓词或比较函数。
标准库预先定义了些function object。所谓
function object
,是某种class的实例对象,这类class对function call运算符做了重载操作,如此一来可使function object被当成一般函数来使用。function object实现了我们原本可能以独立函数加以定义的事物。但又何必如此呢?标准库事先定义了一组
主要是为了效率。我们可以令call运算符成为inline,从而消除“通过函数指针来调用函数”时需要付出的额外代价。
function object
,分为:算术运算(
arithmetic
)、关系运算(relational
)和逻辑运算(logical
)三大类。以下列表中的type在实际使用时会替换为内置类型或class类型:
6个算术运算 | plus multiplies |
6个关系运算 | less greater_equal |
3个逻辑运算 | logical_and |
functional
>默认情况下sort()是升序排列,我们将元素降序排列:
sort(vec.begin(), vec.end(), greater());
其中的greater
binary_search()期望其搜索对象先经过排序,为了正确搜索vector,就必须传给它某个
function object object
,供vector排序使用:binary_search(vec.begin(), vec.end(), elem, greater());
我们对Fibonacci数列可以做些其他操作,如:每个元素和自身相加、和自身相乘、被加到对应的Pell数列等等。做法之一是使用泛型算法transform()并搭配plus
我们必须传给transform()的参数有:
?一对iterator,标示出欲转换的元素范围;
?一个iterator,所指元素将应用于转换上,元素范围同?;
?一个iterator,所指位置(及其后面的空间)用来存放转换结果;
?一个function object,表现出我们想要应用的转换操作。
以下是将Pell数列加到Fibonacci数列的写法:
transform(fib.begin(), fib.end(), //?pell.begin(),//?fib_plus_pell.begin(),//?plus); //?
transform()的定义:
function templatestd::transform
unary operation(1) templateOutputIterator transform(InputIterator first1, InputIterator last1,OutputIterator result, UnaryOperation op); binary operation(2) template OutputIterator transform(InputIterator1 first1, InputIterator1 last1,InputIterator2 first2, OutputIterator result,BinaryOperation binary_op); ————————————————————————————————————————————————————将操作顺序应用于一(1)或两(2)个范围的元素,并将结果存储在从结果开始的范围中。(1) 一元操作将op应用于[first1,last1]范围内的每个元素,并将每个操作返回的值存储在从result开始的范围内。(2) 二元操作使用范围[first1,last1]中的每个元素作为第一个参数,并使用范围中从first2开始的各个参数作为第二个参数来调用binary_op。每个调用返回的值存储在从result开始的范围中。 该函数允许目标范围与其中一个输入范围相同,以便进行适当的转换。
函数对象适配器:
function object less
真的可以做到这样吗?是的。标准库提供adapter(适配器)便应此而生。
function object adapter会对function object进行修改操作。binder adapter(绑定适配器)会将function object的参数绑定至某特定值,使binary(二元) function object转化为unary(一元)function object。这正是我们需要的。标准库提供了两个
binder adapter
:bind1st
会将指定值绑定至第一操作数;bind2nd
将指定值绑定至第二操作数。如:a < b,则a是第一操作数,b是第二操作数。
vectorfilter &vec, int val, less <) { vector nvec; vector ::const_iterator iter = vec.begin(); while ((iter = find_if(iter, vec.end(), bind2nd(lt, val))) != vec.end()) {nvec.push_back(*iter); iter++; } return nvec; }
bind2nd(less, val)
;
会把val绑定于lessfind_if()
的定义如下:templateInputIterator find_if(InputIterator first, InputIterator last, UnaryPredicate pred); ●first、last:输入迭代器到序列的初始和最终位置。使用的范围是[first,last),它包含first和last之间的所有元素,包括first指向的元素,但不包括last指向的元素。●pred:接受范围内的元素作为参数并返回可转换为bool类型的值的【一元函数】。返回的值表明该元素是否被认为是此函数的上下文中的匹配。 函数不能修改它的参数。 它可以是函数指针,也可以是函数对象(function object)。●返回值:指向pred不返回false的范围内第一个元素的迭代器。 如果pred对所有元素都为false,则函数返回last。这个函数模板的行为相当于:template InputIterator find_if(InputIterator first, InputIterator last, UnaryPredicate pred) {while (first!=last) {if (pred(*first)) return first; ++first; }return last; }
下面看一个泛型函数find_if()的例子:
#include// std::cout#include// std::find_if#include // std::vectorbool IsOdd (int i) {return ((i%2)==1); }int main () {std::vector myvector; myvector.push_back(10); myvector.push_back(25); myvector.push_back(40); myvector.push_back(55); std::vector ::iterator it = std::find_if(myvector.begin(), myvector.end(), IsOdd); std::cout << "The first odd value is " << *it << '\n'; return 0; }
The first odd value is 25
看一个bind2nd()和bind1st()的例子:
#include#include #include using namespace std; int main () { int numbers[] = {10,-20,-30,40,-50}; int cx = count_if(numbers, numbers+5, bind2nd(less (), 0)); cout << "There are " << cx << " negative elements.\n"; return 0; }
There are 3 negative elements.
#include#include #include using namespace std; int main () { int numbers[] = {10,-20,-30,40,-50}; int cx = count_if(numbers, numbers+5, bind1st(less (), 0)); cout << "There are " << cx << " positive elements.\n"; return 0; }
There are 2 positive elements.
总结 【一起来学习C++的函数指针和函数对象】本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!
推荐阅读
- 基于QT设计一个春联自动生成器
- OpenCV2学习笔记之视频流读取与处理
- 一文让你明白CPU上下文切换
- async-validator|async-validator 源码学习笔记(三)(rule)
- 互联网后端技术栈一览,写得太好了!
- 关于 Java 18 你想知道的一切
- 小公司的前端建设的一些思考
- c/c++技术|小白 C++ 入门到大神发疯学习路线
- C语言与C++编程|C语言学习方法、学习平台及项目推荐
- linux学习|[linux]十、文件目录权限(permission)及归属-part1