C++operator()(重载⼩括号运算符)
分类专栏:C++总结重载⼩括号运算符⽂章标签:operator()重载⼩括号运算符仿函数
版权
在C++语⾔中有时候需要重载运算符:(),今天我们主要介绍它主要应⽤的场合。
仿函数
先考虑⼀个简单的例⼦:假设有⼀个vector,你的任务是统计长度⼩于5的string的个数,如果使⽤count_if函数的话,你的代码可能长成
这样:
其中count_if函数的第三个参数是⼀个函数指针,返回⼀个bool类型的值。⼀般的,如果需要将特定的阈值长度也传⼊的话,我们可能将函
数写成这样:
这个函数看起来⽐前⾯⼀个版本更具有⼀般性,但是他不能满⾜count_if函数的参数要求:count_if要求的是unaryfunction(仅带有⼀个
参数)作为它的最后⼀个参数。所以问题来了,怎么样找到以上两个函数的⼀个折中的解决⽅案呢?
这个问题其实可以归结于⼀个dataflow的问题,要设计这样⼀个函数,使其能够access这个特定的length值,回顾我们已有的知识,有2
种解决⽅案可以考虑:
函数的参数:
这种⽅法我们已经讨论过了,多个参数不适⽤于count_if函数;
全局变量:
我们可以将长度阈值设置成⼀个全局变量,代码可能像这样:
这段代码看似很不错,实则不符合规范,刚重要的是,它不优雅。原因有以下⼏点要考虑:
容易出错:
为什么这么说呢,我们必须先初始化maxLength的值,才能继续接下来的⼯作,如果我们忘了,则可能⽆法得到正确答案。此外,变量
maxLength和函数LengthIsLessThan之间是没有必然联系的,编译器⽆法确定在调⽤该函数前是否将变量初始化,给码农平添负担;
没有可拓展性:
如果我们每遇到⼀个类似的问题就新建⼀个全局变量,尤其是多⼈合作写代码时,很容易引起命名空间污染(namespacepolution)的问
题;当范围域内有多个变量时,我们⽤到的可能不是我们想要的那个;
全局变量的问题:
每当新建⼀个全局变量,即使是为了coding的便利,我们也要知道我们应该尽可能的少使⽤全局变量,因为它的cost很⾼;⽽且可能暗⽰
你这⾥有⼀些待解决的优化⽅案。
说了这么多,还是要回到我们原始的那个问题,有什么解决⽅案呢?答案当然就是这篇⽂章的主题部分:仿函数。我们的初衷是想设计⼀个
unaryfunction,使其能做binaryfunction的⼯作,这看起来并不容易,但是仿函数能解决这个问题。
1boolLengthIsLessThanFive(conststring&str){
()<5;
3}
4intres=std::count_if((),(),LengthIsLessThanFive);
1boolLenthIsLessThan(conststring&str,intlen){
()
3}
1intmaxLength;
2boolLengthIsLessThan(conststring&str){
()
4}
5intres=std::count_if((),(),LengthIsLessThan);
先来看仿函数的通俗定义:仿函数(functor)⼜称为函数对象(functionobject)是⼀个能⾏使函数功能的类。仿函数的语法⼏乎和我们
普通的函数调⽤⼀样,不过作为仿函数的类,都必须重载operator()运算符,举个例⼦:
仿函数其实是上述解决⽅案中的第3种⽅案:成员变量。成员函数可以很⾃然的访问成员变量:
我相信这个例⼦能让你体会到⼀点点仿函数的作⽤了;它既能想普通函数⼀样传⼊给定数量的参数,还能存储或者处理更多我们需要的有⽤
信息。
让我们回到count_if的问题中去,是不是觉得问题变得豁然开朗了?
count_if((),(),ShorterThan(length));//直接调⽤即可
这⾥需要注意的是,不要纠结于语法问题:ShorterThan(length)似乎并没有调⽤operator()函数?其实它调⽤了,创建了⼀个临时对象。
你也可以⾃⼰加⼀些输出语句看⼀看。
1classFunc{
2public:
3voidoperator()(conststring&str)const{
4cout<
5}
6};
7FuncmyFunc;
8myFunc("helloworld!");
9output:helloworld!
1classStringAppend{
2public:
3explicitStringAppend(conststring&str):ss(str){}
4
5voidoperator()(conststring&str)const{
6cout<
7}
8
9private:
10conststringss;
11};
12
13StringAppendmyFunc("isworld");
14myFunc("hello");
15output:helloisworld
1classShorterThan{
2public:
3explicitShorterThan(intmaxLength):length(maxLength){}
4booloperator()(conststring&str)const{
()
6}
7private:
8constintlength;
9};
类型转换
C++中可以定义类型转换函数,将类对象转换为其他类型,函数原型为:operatorType()类型转换函数与转换构造函数具有同等的地位;
类型转换函数使得编译器有能⼒将对象转化为其他类型;
编译器能够隐式的使⽤类型转换函数;
转换为普通数据类型
1#include
2#include
3usingnamespacestd;
4classTest
5{
6
7public:
8Test(inti=0)
9{
10mValue=i;
11}
12intvalue()
13{
14returnmValue;
15}
16operatorint()
17{
18returnmValue;
19}
20
21private:
22intmValue;
23};
24
25intmain()
26{
27Testt(100);
28inti=t;
29
30cout<<"()="<<()<
31cout<<"i="<
32
33return0;
34}
35
36类类型之间的转换
37#include
38#include
39
40classTest;
41
42classValue
43{
44public:
45Value()
46{
47
48}
49
50Value(Test&t)//fal
51//explicitValue(Test&t)//Ok
52{
53std::cout<<"explicitValue(Test&t)"<
54}
55};
56
57classTest
从输出结果我们可以发现:转换构造函数和类型转换函数发⽣冲突了,编译器不知道应该调⽤哪个函数。因此发⽣了错误。
当然我们可以使⽤explicit关键字抑制隐式的转换构造函数,让程序只调⽤类型转换函数。但是,我们⽆法抑制隐式的类型转换函数。
57classTest
58{
59intmValue;
60
61public:
62Test(inti=0)
63{
64mValue=i;
65}
66
67intvalue()
68{
69returnmValue;
70}
71
72operatorValue()
73{
74Valueret;
75std::cout<<"operatorValue()"<
76returnret;
77}
78};
79
80intmain()
81{
82Testt(100);
83Valuev=t;
84
85return0;
86}
本文发布于:2022-12-30 15:11:08,感谢您对本站的认可!
本文链接:http://www.wtabcd.cn/fanwen/fan/90/60518.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |