这篇文章主要介绍“C++的operator()怎么使用”,在日常操作中,相信很多人在C++的operator()怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C++的operator()怎么使用”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
在C++语言中有时候需要重载运算符: (),今天我们主要介绍它主要应用的场合。
仿函数
先考虑一个简单的例子:假设有一个vector,你的任务是统计长度小于5的string的个数,如果使用count_if函数的话,你的代码可能长成这样:
bool LengthIsLessThanFive(const string& str) {
return str.length() < 5;
}
int res = std::count_if(vec.begin(), vec.end(), LengthIsLessThanFive);
其中count_if函数的第三个参数是一个函数指针,返回一个bool类型的值。一般的,如果需要将特定的阈值长度也传入的话,我们可能将函数写成这样:
bool LenthIsLessThan(const string& str, int len) {
return str.length()<len;
}
这个函数看起来比前面一个版本更具有一般性,但是他不能满足count_if函数的参数要求:count_if要求的是unary function(仅带有一个参数)作为它的最后一个参数。所以问题来了,怎么样找到以上两个函数的一个折中的解决方案呢?
这个问题其实可以归结于一个data flow的问题,要设计这样一个函数,使其能够access这个特定的length值,回顾我们已有的知识,有2种解决方案可以考虑:
函数的参数:
这种方法我们已经讨论过了,多个参数不适用于count_if函数;
全局变量:
我们可以将长度阈值设置成一个全局变量,代码可能像这样:
int maxLength;
bool LengthIsLessThan(const string& str) {
return str.length() < maxLength;
}
int res = std::count_if(vec.begiin(), vec.end(), LengthIsLessThan);
这段代码看似很不错,实则不符合规范,刚重要的是,它不优雅。原因有以下几点要考虑:
容易出错:
为什么这么说呢,我们必须先初始化maxLength的值,才能继续接下来的工作,如果我们忘了,则可能无法得到正确答案。此外,变量maxLength和函数LengthIsLessThan之间是没有必然联系的,编译器无法确定在调用该函数前是否将变量初始化,给码农平添负担;
没有可拓展性:
如果我们每遇到一个类似的问题就新建一个全局变量,尤其是多人合作写代码时,很容易引起命名空间污染(namespace polution)的问题;当范围域内有多个变量时,我们用到的可能不是我们想要的那个;
全局变量的问题:
每当新建一个全局变量,即使是为了coding的便利,我们也要知道我们应该尽可能的少使用全局变量,因为它的cost很高;而且可能暗示你这里有一些待解决的优化方案。
说了这么多,还是要回到我们原始的那个问题,有什么解决方案呢?答案当然就是这篇文章的主题部分:仿函数。我们的初衷是想设计一个unary function,使其能做binary function的工作,这看起来并不容易,但是仿函数能解决这个问题。
先来看仿函数的通俗定义:仿函数(functor)又称为函数对象(function object)是一个能行使函数功能的类。仿函数的语法几乎和我们普通的函数调用一样,不过作为仿函数的类,都必须重载operator()运算符,举个例子:
class Func{
public:
void operator() (const string& str) const {
cout<<str<<endl;
}
};
Func myFunc;
myFunc("helloworld!");
output: helloworld!
仿函数其实是上述解决方案中的第3种方案:成员变量。成员函数可以很自然的访问成员变量:
class StringAppend{
public:
explicit StringAppend(const string& str) : ss(str){}
void operator() (const string& str) const{
cout<<str<<' '<<ss<<endl;
}
private:
const string ss;
};
StringAppend myFunc("is world");
myFunc("hello");
output: hellois world
我相信这个例子能让你体会到一点点仿函数的作用了;它既能想普通函数一样传入给定数量的参数,还能存储或者处理更多我们需要的有用信息。
让我们回到count_if的问题中去,是不是觉得问题变得豁然开朗了?
class ShorterThan {
public:
explicit ShorterThan(int maxLength) : length(maxLength) {}
bool operator() (const string& str) const {
return str.length() < length;
}
private:
const int length;
};
count_if(myVector.begin(), myVector.end(), ShorterThan(length)); //直接调用即可
这里需要注意的是,不要纠结于语法问题:ShorterThan(length)似乎并没有调用operator()函数?其实它调用了,创建了一个临时对象。你也可以自己加一些输出语句看一看。
类型转换
C++中可以定义类型转换函数,将类对象转换为其他类型,函数原型为:operator Type()
类型转换函数与转换构造函数具有同等的地位;
类型转换函数使得编译器有能力将对象转化为其他类型;
编译器能够隐式的使用类型转换函数;
转换为普通数据类型
#include <iostream>
#include <string>
using namespace std;
class Test
{
public:
Test(int i = 0)
{
mValue = i;
}
int value()
{
return mValue;
}
operator int ()
{
return mValue;
}
private:
int mValue;
};
int main()
{
Test t(100);
int i = t;
cout << "t.value() = " << t.value() << endl;
cout << "i = " << i << endl;
return 0;
}
类类型之间的转换
#include <iostream>
#include <string>
class Test;
class Value
{
public:
Value()
{
}
Value(Test& t) // false
// explicit Value(Test& t) // Ok
{
std::cout << "explicit Value(Test& t)" << std::endl;
}
};
class Test
{
int mValue;
public:
Test(int i = 0)
{
mValue = i;
}
int value()
{
return mValue;
}
operator Value()
{
Value ret;
std::cout << "operator Value()" << std::endl;
return ret;
}
};
int main()
{
Test t(100);
Value v = t;
return 0;
}
从输出结果我们可以发现:转换构造函数和类型转换函数发生冲突了,编译器不知道应该调用哪个函数。因此发生了错误。
当然我们可以使用explicit关键字抑制隐式的转换构造函数,让程序只调用类型转换函数。但是,我们无法抑制隐式的类型转换函数
到此,关于“C++的operator()怎么使用”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。