C++中重载函数调用运算符

C++中重载函数调用运算符

如果类重载了函数调用运算符,则我们可以像使用函数一样使用该类的对象。因为这样的类同时也能存储状态,所以与普通函数相比它们

更加灵活。

举个简单的例子,下面这个名为 absInt 的 struct 含有一个调用运算符,该运算符负责返回其参数的绝对值:

struct absInt
{
    int operator()(int val) const 
    {
        return val < 0 ? -val : val;
    }
}

这个类只定义了一种操作:函数调用运算符,它负责接受一个 int 类型的实参,然后返回该实参的绝对值。

我们使用调用运算符的方式是令一个 absInt 对象作用于一个实参列表,这一过程看起来非常像调用函数的过程:

int i = -42;
absInt absObj;            //含有函数调用运算符的对象
int ui = absObj(i);       //将传递给absObj.operator()

即使 absObj 只是一个对象而非函数,我们也能 “调用” 该对象。调用对象实际上是在运行重载的调用运算符。在此例中,该运算符接受一个 int 值并返回其绝对值。

函数调用运算符必须是成员函数。一个类可以定义多个不同版本的调用运算符,相互之间应该在参数数量或类型上有所区别。

如果类定义了调用运算符,则该类的对象称作函数对象(function object)。因为可以调用这种对象,所以我们说这些对象的 “行为像函

数一样”。

含有状态的函数对象类

和其他类一样,函数对象类除了 operator() 之外也可以包含其他成员。函数对象类通常含有一些数据成员,这些成员被用于定制调用

运算符中的操作。

举个例子,我们将定义一个打印 string 实参内容的类。默认情况下,我们的类会将内容写入到 cout 中,每个 string 之间以空格隔开。同

时也允许类的用户提供其他可写入的流及其他分隔符。我们将该类定义如下:

class PrintString
{
public:
    PrintString(ostream &o = cout, char c= ' '):
         os(o), sep(c) { }
    void operator()(const string &s) const { os << s << sep; }
private:
    ostream &os;    //用于写入的目的流
    char sep;       //用于将不同输出隔开的字符
};

我们的类有一个构造函数,它接受一个输出流的引用以及一个用于分隔的字符,这两个形参的默认实参分别是 cout 和 空格。之后的函数

调用运算符使用这些成员协助其打印给定的 string。

当定义 Printstring 的对象时,对于分隔符及输出流既可以使用默认值也可以提供我们自己的值:

PrintString printer;   // 使用默认值,打印到 cout
printer(s);            // 在cout中打印s,后面跟一个空格
PrintString errors(cerr, '\n');
errors(s);             //在cerr中打印s,后面跟一个换行符

函数对象常常作为泛型算法的实参。例如,可以使用标准库 for_each 算法和我们自己的 PrintString 类来打印容器的内容:

for_each(vs.begin(), vs.end(), PrintString(cerr, '\n'));

for_each 的第三个实参是类型 PrintString 的一个临时对象,其中我们用 cerr 和换行符初始化了该对象。当程序调用 for_each 时,将会把 vs 中的每个元素依次打印到 cerr 中,元素之间以换行符分隔。

该文章会更新,欢迎大家批评指正。

推荐一个零声学院免费公开课程,个人觉得老师讲得不错,
分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,
fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,
TCP/IP,协程,DPDK等技术内容,点击立即学习:
服务器课程:C++服务器

你可能感兴趣的:(CC++编程要点,c++)