操作运算符operator在C++中运用的很频繁,各种类的运算符重载都要用到它,但是本章是为函数对象做铺垫。
本文仅供个人记录和复习,不用于其他用途
函数运算符operator()
重载运算符的部分不再赘述,我们这里只针对函数运算符operator()
进行分析。函数运算符一般用于标准模板库(STL)中,通常是STL算法中。一般来说,函数对象可分为单目谓词和双目谓词。
简单举例
|
|
上面是一个十分简单的例子,我们在CDisplay
类中对()
进行了定义,使得对象可以像函数一样。事实上,这个运算符被称作operator()
函数,对象CDisplay
也被称为函数对象或者functor
。
移动构造函数和移动赋值运算符
这两个主要用于性能优化,避免复制不必要的临时值。
问题引入
|
|
类似于上面的这个类,如果对加法运算符进行了重载,那么一般就会返回一个拷贝,减法运算符也是如此。如果我们新建一个MyString
类,也使用这种重载方法会怎么样呢?
|
|
如果一个类重载了加法运算符,那么就会返回一个拷贝。虽然加法运算符可以轻松地拼接字符串,不过也会导致一些性能问题。创建sayHello
时,需要执行加法运算符两次,每次都要创建一个按值返回的临时拷贝。也就是说,我们在这里使用了两次复制构造函数,执行了深复制。但事实上,临时拷贝在表达式执行完毕之后就不需要了,我们并不需要深复制。
代码实例
为了解决这个问题,我们需要使用移动构造函数和移动赋值运算符:
|
|
相比于常规赋值构造函数和复制赋值运算符的声明,移动构造函数和移动赋值运算符的不同之处就在于,输入参数的类型为MyClass &&
。这两种只是将资源从源移动到目的地。两个&&
代表右值引用,不会进行复制。
这里为了详细的解释这四种函数,提供了一个模板:
|
|
控制台输出如下:
Constructor called for:Hello
Constructor called for:World
Constructor called for: of C++
Constructor called for:overwrite this
operator + called:
Default constructor called
Move constructor to move from:Hello World
operator + called:
Default constructor called
Move constructor to move from:Hello World of C++
Move assignment operator to move from:Hello World of C++
事实上,移动的就是传入参数为MyClass &&
。另外呢,由于输入参数是要移动的源对象,所以不能使用cosnt
限定。总之,只要创建临时右值时,C++编译器便会使用移动的函数。
移动的函数其实就是接管移动源中的资源所有权,而复制的则是分配新的空间,然后将移动源的信息拷贝进来。
题外话
事实上,把构造函数、复制赋值运算符、复制构造函数等等声明为私有,是为了实现单例模式。当然,如果单纯只是想阻止栈上实例化(比如占据内存较大的数据库类),就可以将析构函数声明为私有。这样一来,编译器在编译过程中就会因为析构函数为私有,从而终止栈上实例化。但是呢,堆上的实例化是可行的,不过我们需要定义一个类成员函数,用来执行delete
。