函数对象,由类实现,类有属性,实例化为对象后表现为对象的状态。类可以重载函数运算符(),对象对此运算符的调用看起来就如果函数的调用一样,不同的是,这是一个对象,所以有其状态,这是其与普通函数的独到之处,有其独特的适用场景。 看下面的实例:includeiostreamincludelistincludeusingnamespacestd;boollargerthan80(doublex){returnx80;}voidfunc(listdoublev){listdouble::iteratorpfindif(v。begin(),v。end(),largerthan80);if(p!v。end()){coutpendl;}}intmain(){doublearr〔〕{66,88,55,44,66,77,99,86,67};listdoublelst(arr,arrsizeof(arr)sizeof(arr));func(lst);getchar();return0;} 如果谓词函数想更改为boollargerthan60(doublex){returnx60;} 显然这不是一种便捷的方法,把代码写死(硬编码,hardcoded)是不好的,于是,函数指针和函数对象就可以登场了:includeiostreamincludelistincludeusingnamespacestd;boollargerthan80(doublex){returnx80;}voidfunc(listdoublev){listdouble::iteratorpfindif(v。begin(),v。end(),largerthan80);if(p!v。end()){coutpendl;}}voidfunc2(listdoublev){classCLargerthan{intv;public:CLargerthan(intvv):v(vv){}storetheargumentbooloperator()(intx)const{returnxv;}compare};CLargerthanLargerthan(70);listdouble::iteratorpfindif(v。begin(),v。end(),Largerthan);if(p!v。end()){coutpendl;}}intmain(){doublearr〔〕{66,88,55,44,66,77,99,86,67};listdoublelst(arr,arrsizeof(arr)sizeof(arr));func(lst);func2(lst);getchar();return0;} 显然,函数对象有更大的灵活性。 通常重载函数调用运算符的函数体都只有几行代码,可以inline,由此,相对于函数指针来说,效率更高。与此同时,函数对象可以嵌在函数内定义,而使用函数指针引用的函数无法嵌套,所以使用函数对象可以让代码更加紧凑。 函数对象带有状态。函数对象相对于普通函数是智能函数,这就如同智能指针相较于传统指针。因为函数对象除了提供函数调用符方法,还可以拥有其他方法和数据成员。所以函数对象有状态。即使同一个类实例化的不同的函数对象其状态也不相同,这是普通函数所无法做到的。而且函数对象是可以在运行时创建。 每个函数对象有自己的类型:对于普通函数来说,只要签名一致,其类型就是相同的。但是这并不适用于函数对象,因为函数对象的类型是其类的类型。这样,函数对象有自己的类型,这意味着函数对象可以用于模板参数,这对泛型编程有很大提升。 函数对象一般快于普通函数,因为其可以inline实现。函数对象一般用于模板参数,模板一般会在编译时会做一些优化。 但函数对象这种代码的写法似乎有点冗余,于是Lambda表达式便登场了。 Lambda表达式是从类创建函数的精简方式。这里讲的类,它仅有的成员就是函数调用运算符。Lambda表达式取消了类声明,并且使用了精简的符号来表示函数调用运算符的逻辑。classLessThan{public:booloperator()(inta,intb){returnab;}} 上面的类只有有一个成员,就是重载了函数调用运算符,写了这么多,核心的语句就只有一句:returnab; 同样的功能,Lambda表达式更简洁,更紧凑,更匿名。〔〕(autoa,autob){returnab;} 以下是使用Lambda表达式的代码:voidfunc3(listdoublev){listdouble::iteratorpfindif(v。begin(),v。end(),〔〕(doublea){returna60;});if(p!v。end()){coutpendl;}} Lambda表达式是函数对象的语法糖。 函数对象可以实现更复杂的功能,而用lambda表达式则需要复杂的引用捕捉。考虑一个可以计算均值的函数对象:classMeanValue{public:MeanValue():num{0},sum{0}{}voidoperator()(inte){num;sumnum;}doublevalue(){returnstaticcastdouble(sum)staticcastdouble(num);}private:intnum;intsum;};intmain(){vectorintv{1,3,5,7};MeanValuemvstd::foreach(v。begin(),v。end(),MeanValue{});coutmv。value()endl;output:2。5return0;} 使用引用捕捉的lambda表达式:intmain(){intx10;autoaddx〔x〕(inta){returnax;};复制捕捉xautomultiplyx〔x〕(inta){returnax;};引用捕捉xcoutaddx(10)multiplyx(10)endl;输出:20100return0;} 主要的语法形式: 〔〕:默认不捕获任何变量; 〔〕:默认以值捕获所有变量; 〔〕:默认以引用捕获所有变量; 〔x〕:仅以值捕获x,其它变量不捕获; 〔x〕:仅以引用捕获x,其它变量不捕获; 〔,x〕:默认以值捕获所有变量,但是x是例外,通过引用捕获; 〔,x〕:默认以引用捕获所有变量,但是x是例外,通过值捕获; 〔this〕:通过引用捕获当前对象(其实是复制指针); 〔this〕:通过传值方式捕获当前对象; 其参数还可以自动推断:autoadd〔〕(autox,autoy){returnxy;};intxadd(2,3);5doubleyadd(2。5,3。5);6。0 ref: https:www。cnblogs。comAlainGaop10675201。html End