前情回顾
第四层中,我遇到了一个很新奇的力量,叫做友元,可以把一些人变成好朋友的神奇力量,除此之外,还学习到了,类内声明函数,类外进行定义的操作,同时,也踏入了第五层…
🚄上章地址:第四层:友元与函数成员别样定义
运算符重载
黑黝黝的洞口,一个人影在缓缓出现,“我就知道你肯定可以掌握友元的,这次需要你掌握另一种重载的力量——运算符重载,祝你好运…”。“新的重载吗…”。
概念
对已有的运算符进行重新定义,赋予其另一种功能,以适应各种不同的运算类型
为什么会出现运算符重载
对于内置的数据类型,编译器知道如何运算,但是对于自定义类型,是不知道如何去运算的,这个时候就需要运算符重载,本质上,是写一个函数来告诉编译器。
运算符重载中函数名格式
对于运算符重载中,上面提到,本质上是写一个函数,不同的人对于函数的命名方式是不一样的,这样编译器也不好识辨,这个函数是不是在实现运算符重载,所以编译器提供了一个固定的格式:
operator+(这里这个加号可以替换成别的符号,当你要对什么符号进行运算符重载时就用什么符号)
加减运算符重载
作用
实现两个自定义数据类型的相加减运算
实现
上面提到对于内置数据类型编译器可以知道如何去运算,而自定义类型是不知道的,那现在有一个类,它有三个对象,其中一个对象等于其他两个对象加起来,要怎么实现,可以先验证直接用+能不能进行:
#include<iostream> using namespace std; class A { public: A() { } A(int a, int b) { _a = a; _b = b; } int _a; int _b; }; void test1() { A a1(10, 10); A a2(10, 10); A a3; a3 = a1 + a2; } int main() { test1(); return 0; }
报错了,没有与这些操作数匹配的“+”运算符,这个错误说明了编译器是不知道对象内部怎么进行加减的,那设计一个函数,函数名字用上面提到的operate+:
#include<iostream> using namespace std; class A { public: A() { } A(int a, int b) { _a = a; _b = b; } A operator+(A &a1) { A tmp; tmp._a = this->_a + a1._a; tmp._b = this->_b + a1._b; return tmp; } int _a; int _b; }; void test1() { A a1(10, 10); A a2(10, 10); A a3; a3 = a1 + a2; cout << a3._a<<" "<< a3._b; } int main() { test1(); return 0; }
其实这中写法的本质还是调用函数,即:
a3=a1+a2 == a3=a1.operator+(a2)
同时也可以把这个改成类外的全局函数,这个时候传参就需要传两个,内部改一下:
#include<iostream> using namespace std; class A { public: A() { } A(int a, int b) { _a = a; _b = b; } //A operator+(A &a1) //{ // A tmp; // tmp._a = this->_a + a1._a; // tmp._b = this->_b + a1._b; // return tmp; //} int _a; int _b; }; A operator+(A& a1, A& a2) { A tmp; tmp._a = a1._a + a2._a; tmp._b = a1._b + a2._b; return tmp; } void test1() { A a1(10, 10); A a2(10, 10); A a3; a3 = a1 + a2; cout << a3._a<<" "<< a3._b; } int main() { test1(); return 0; }
也是可以正常跑起来的。
减号同理,与加号实现原理一致,只需要把+换成-。
#include<iostream> using namespace std; class A { public: A() { } A(int a, int b) { _a = a; _b = b; } //A operator+(A &a1) //{ // A tmp; // tmp._a = this->_a + a1._a; // tmp._b = this->_b + a1._b; // return tmp; //} int _a; int _b; }; A operator-(A& a1, A& a2) { A tmp; tmp._a = a1._a - a2._a; tmp._b = a1._b - a2._b; return tmp; } void test1() { A a1(10, 10); A a2(10, 10); A a3; a3 = a1 - a2; cout << a3._a<<" "<< a3._b; } int main() { test1(); return 0; }
左移运算符重载
作用
可以输出自定义的数据类型
左移运算符是什么?
左移运算为程序员调用cout的时候,会在后面加“<<”,这个就是左移运算符
实现
同样,可以直接用cout来进行只用类就把类内属性都打印出来吗:
#include<iostream> using namespace std; class A { public: A() { } A(int a, int b) { _a = a; _b = b; } //A operator+(A &a1) //{ // A tmp; // tmp._a = this->_a + a1._a; // tmp._b = this->_b + a1._b; // return tmp; //} int _a; int _b; }; A operator-(A& a1, A& a2) { A tmp; tmp._a = a1._a - a2._a; tmp._b = a1._b - a2._b; return tmp; } void test1() { A a1(10, 10); A a2(10, 10); A a3(0, 0); a3 = a1 - a2; cout << a3 << endl ; } int main() { test1(); return 0; }
明显是不可以的,那要怎么样进行改造呢?如果是成员函数呢?传参和返回类型是什么?返回类型暂定为void,那参数呢?cout吗?那传参cout简化就变成了:
对象<
放的顺序不一样,所以成员函数无法实现,那就用全局函数,用之前,需要探究一个事情,cout是什么类型?转到定义看一下:
cout的类型就是ostream,那类型解决了,还有什么注意事项吗?有,并且很重要:
对于全局来说,只有一个cout,所以cout是需要进行引用的,对象也是需要进行引用才可以。
#include<iostream> using namespace std; class A { public: A() { } A(int a, int b) { _a = a; _b = b; } //A operator+(A &a1) //{ // A tmp; // tmp._a = this->_a + a1._a; // tmp._b = this->_b + a1._b; // return tmp; //} int _a; int _b; }; A operator-(A& a1, A& a2) { A tmp; tmp._a = a1._a - a2._a; tmp._b = a1._b - a2._b; return tmp; } void operator<<(ostream& cout, A& a3) { cout << a3._a << " " << a3._b; } void test1() { A a1(10, 10); A a2(10, 10); A a3(0, 0); a3 = a1 - a2; cout << a3 << endl; } int main() { test1(); return 0; }
为什么这里还是有报错?对于cout这种能一直在后面追加编程,称作链式编程,在前面的this指针中,提到过一种用途,这里也要用到,因为返回的是void,所以对于endl来说,前面的就不是cout,所以就不能进行输出,那这里就需要返回一个cout,cout的类型,同时记得加引用:
#include<iostream> using namespace std; class A { public: A() { } A(int a, int b) { _a = a; _b = b; } //A operator+(A &a1) //{ // A tmp; // tmp._a = this->_a + a1._a; // tmp._b = this->_b + a1._b; // return tmp; //} int _a; int _b; }; A operator-(A& a1, A& a2) { A tmp; tmp._a = a1._a - a2._a; tmp._b = a1._b - a2._b; return tmp; } ostream& operator<<(ostream& cout, A& a3) { cout << a3._a << " " << a3._b; return cout; } void test1() { A a1(10, 10); A a2(10, 10); A a3(0, 0); a3 = a1 - a2; cout << a3 << endl; } int main() { test1(); return 0; }
递增递减运算符
作用
通过重载递增递减预算符,实现自己类内的整型数据
实现
前置
前置的递增递减是前++(- -),在使用,所以可以先在实现的函数内部先进行++(- -),在返回引用,这里为什么要返回引用呢?如果不返回引用,那就是对局部这个变量进行了++(- -),多次使用++(- -),本身只会生成一次,因为不是引用,会产生拷贝,把数据拷贝到新的空间上:
使用引用
#include<iostream> using namespace std; class A { public: A() { } A(int a, int b) { _a = a; _b = b; } A& operator++() { this->_a++; this->_b++; return *this; } //A operator+(A &a1) //{ // A tmp; // tmp._a = this->_a + a1._a; // tmp._b = this->_b + a1._b; // return tmp; //} int _a; int _b; }; A operator-(A& a1, A& a2) { A tmp; tmp._a = a1._a - a2._a; tmp._b = a1._b - a2._b; return tmp; } ostream& operator<<(ostream& cout, A& a3) { cout << a3._a << " " << a3._b; return cout; } void test1() { A a1(10, 10); A a2(10, 10); A a3(0, 0); a3 = a1 - a2; cout << ++(++a3) << endl; } int main() { test1(); return 0; }
不使用引用
#include<iostream> using namespace std; class A { public: A() { } A(int a, int b) { _a = a; _b = b; } A operator++() { this->_a++; this->_b++; return *this; } //A operator+(A &a1) //{ // A tmp; // tmp._a = this->_a + a1._a; // tmp._b = this->_b + a1._b; // return tmp; //} int _a; int _b; }; A operator-(A& a1, A& a2) { A tmp; tmp._a = a1._a - a2._a; tmp._b = a1._b - a2._b; return tmp; } ostream& operator<<(ostream& cout, A& a3) { cout << a3._a << " " << a3._b; return cout; } void test1() { A a1(10, 10); A a2(10, 10); A a3(0, 0); a3 = a1 - a2; cout << ++(++a3) << endl; } int main() { test1(); return 0; }
直接是报错的。
前置递减实现也相同,将++换成–即可。