运算符重载
运算符重载分为两种形式,一种是成员函数重载,一种是全局函数重载。
- +重载
采用成员和全局重载的方法是相同的结果的,但是请注意全局重载有两个参数第一个参数是加号左边的值,第二个参数是加号右边的值;而对于成员函数重载只有一个参数,加号左边的对象是重载函数的调用者,加号右 边的对象作为参数传入重载函数。
- <<重载
需要认识到的是,ostream类中,cout对象是单例的,它没有拷贝函数,这就要求对<<重载函数的返回值类型必须是 ostream &。另外,由于cout是左值,调用的对象是右值,所以重载函数必须是全局重载,因为不能是
object << cout。
- ++重载
这包含两种重载类型,一种是前置重载,一种是后置重载。前置递增没有参数,后置递增包含参数。
1.前置重载
在讨论前置递增之前,我们首先研究引用返回和值返回的区别。
此处有一个类Dog,若有一个函数返回值是Dog,我们成为是值返回;如果返回值是Dog &,我们称这种返回叫做引用返回。值返回会产生一个临时变量,return的过程就是使用拷贝函数对临时对象赋值的过程,值得注意的是,临时对象的生命周期比函数内部的局部变量的生命周期更长;而引用返回则不同,return 的过程中不产生临时变量,这样不仅减少了内存资源的消耗,而且便于使返回值作为左值参与运算。
有了上面的分析,我们知道了,对于对此的递增运算,如++(++dog),其中 dog 是Dog类的一个对象,如果采用值返回,在进行了一次运算后,返回的是临时对象,这样dog本身不会在自增,基于此,我们可以得出自增运算符重载的函数返回值必须是引用类型。
2.后置重载
后置递增与前置递增不同,后置递增首先返回该对象的值,再将对象自增。
后置递增的声明:Dog operator++(int),注意后置自增的展位参数必须是 int 类型。
后置递增返回类型必须是值返回,因为下面的代码中,tmp 是局部变量,再执行完自增后,函数中定义的局部变量就会被销毁,这个时候对该对象的访问时非法的。
- =重载
重载首先应该进行深拷贝。
赋值运算符重载需要注意的是,对于连续赋值的情况,如 d1 = d2 =d3; 。这种情况下,重载的方式非常丰富具体可以参见另一位大佬的博客,下面给出链接:
https://www.cnblogs.com/zpcdbky/p/5027481.html
#include <iostream> #include <string> using namespace std; class Dog { private: string name; int age; public: Dog(string name, int age) { cout << "调用参数构造函数。" << endl; this->name = name; this->age = age; } Dog(const Dog& d) { cout << "调用复制构造函数。" << endl; name = d.name; age = d.age; } ~Dog() { cout << "调用析构函数。" << endl; } Dog operator+(Dog& d); Dog& operator++(); Dog operator++(int); Dog operator=(const Dog& d); string getName() const { return name; } int getAge() const { return age; } Dog setAge(int age) { this->age = age; return *this; } void show() { cout << name << '\t' << age << endl; } }; //加号成员函数重载 Dog Dog::operator+(Dog& d) { this->age += d.age; return*this; } //加号全局函数重载 Dog operator+(const Dog& d, int x) { cout << "--------" << endl; Dog tmp(d.getName(), d.getAge()); cout << "--------" << endl; return tmp.setAge(tmp.getAge() + x); } //左移运算符重载 ostream& operator<<(ostream& cout, const Dog& d) { cout << d.getName() << '\t' << d.getAge(); return cout; } //前置递增,返回类型必须是引用返回 Dog& Dog::operator++() { age++; return *this; } //后置递增,返回类型必须是值返回 Dog Dog::operator++(int) { cout << "--------" << endl; Dog tmp = *this; cout << "--------" << endl; age++; cout << "C++17新特性,将返回值优化,对于局部变量的值返回,不再进行复制构造。tmp不再被复制。" << endl; return tmp; } //赋值运算符重载,赋值运算的返回值必须是引用,这样对于连等操作才会合法 Dog Dog::operator=(const Dog& d) { cout << "开始赋值。" << endl; this->name = d.getName(); this->age = d.getAge(); cout << "值返回。" << endl; return *this; } int main() { Dog d1("eta", 0); Dog d2("vii", 1); d1 = d1 + d2; cout << "d1 = " << d1 << endl; cout << "d2 = " << d2 << endl; d2 = d2 + 10; cout << d2 << endl; cout << "d1两次前置递增: " << ++(++d1) << endl; cout << "d2单次后置递增进行时:" << d2++ << endl; cout << "d2后置递增完成后: " << d2 << endl; d1 = d2; cout << "将d1赋值给d2: " << d1 << endl; Dog d3("none", -1); cout << "\n连等:" << endl; d1 = d2 = d3; cout << "连续赋值后:" << endl; cout << "d1: " << d1 << endl; cout << "d2: " << d2 << endl; cout << "d3: " << d3 << endl; cout << "结束。" << endl; return 0; }