文章目录
1、双目运算符(重载时需要两个参数)
+ - * /
- 以+为例
- 以全局函数的形式进行重载
- 以成员函数(隐含第一个参数为this, 且不可更改 )的形式进行重载
/// 全局函数重载 #include<iostream> using namespace std; // 类声明 --> 避免第14行友元函数声明的有效性 class Obj1; class Obj2; class Obj1 { private: int num; public: Obj1(int i = 0) :num(i) {}; friend int operator+(const Obj1& o1, const Obj2& o2);//14行,如果没有Obj2类声明,这里将会出错 }; class Obj2 { private: int num; public: Obj2(int j = 0) :num(j) {}; friend int operator+(const Obj1& o1, const Obj2& o2); }; int operator+(const Obj1& o1, const Obj2& o2) { int temp = o2.num + o1.num; // 下面的this报错--->说明全局函数的重载并不会传入this // cout << "重载运算符内部的this指向--->\r\n" << this << "===========\r\n"; return temp; } int main() { Obj1 oo1(12); Obj2 oo2(13); cout << oo1 + oo2 << endl; return 0; }
ps: this指针
进行成员函数的形式进行重载之前,我们先来理解一下成员函数里面隐含自带的this指针`
this作用域
是在类内部,当在类的非静态成员函数中访问类的非静态成员的时候,编译器会自动将对象本身的地址作为一个隐含参数传递给函数。也就是说,即使你没有写上this指针,编译器在编译的时候也是加上this的,它作为非静态成员函数的隐含形参,对各成员的访问均通过this进行。
- this指针指向当前对象;
#include <iostream> using namespace std; class Date { private: int _year; int _month; int _day; public: Date(int year, int month, int day)//构造函数 { _year = year; _month = month; _day = day; }; void print() { cout << &this->_year << "-----" <<&this->_month<<"----" << &this->_day << "----" << "----\r\n" << this << endl; } }; int main() { Date d(2017, 6, 30); d.print(); return 0; }
- 输出结果:
// cout << &this->_year << "-----" <<&this->_month<<"----" << &this->_day << "----" << "----\r\n" << this << endl; 001CFE50-----001CFE54----001CFE58-------- 001CFE50
- 可以看到this指针指向了year 的地址,这就涉及到了类的内部存储问题了
- 在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。
- this 参考博客
- 以成员函数的形式进行重载
#include<iostream> using namespace std; // 类声明 --> 避免第14行友元函数声明的有效性 class Obj1; class Obj2; class Obj1 { private: int num; public: Obj1(int i = 0) :num(i) {}; friend Obj2& operator+(const Obj1& o1); }; class Obj2 { private: int num; public: Obj2(int j = 0) :num(j) {}; Obj2& operator+(const Obj1& o1); friend ostream& operator<<(ostream& out, Obj2& o2) { cout << o2.num; return out; } }; Obj2& Obj2:: operator+(const Obj1& o1) { cout << &this->num << "==========" << this << "\r\n"; cout << "重载运算符内部的this指向的值--->" << *this << "\r\n===========\r\n"; this->num += 1; cout << "this->num=" << this->num << endl; return *this; }; int main() { Obj1 oo1(12); Obj2 oo2(14); cout << oo2 + oo1 << endl; return 0; }
- 运行结果
00F0F764==========00F0F764
重载运算符内部的this指向的值—>14
===========
this->num=15
15
- ps:
- 如果要实现两个类的加重载,可以使用友元函数进行重载(两个类的引用作为形参)
2、单目运算符
++、–
是否传入
int
区分是前增还是后增
#include<iostream> using namespace std; // 类声明 --> 避免第14行友元函数声明的有效性 class Obj2; class Obj2 { private: int num; public: Obj2(int j = 0) :num(j) {}; friend ostream& operator<<(ostream& out, Obj2& o2) { cout << o2.num <<endl; return out; } Obj2& operator++() { std::cout << "前增量\r\n"; this->num++; return *this;//返回原对象 }; Obj2& operator++(int) { std::cout << "后增量\r\n" ; Obj2 temp(*this); //临时对象存放原有对象的值 this->num++; //原有对象的值++ return temp; //返回原有对象 } }; int main() { Obj2 oo2(14); cout << oo2 << "====>" << &oo2 << endl; oo2++; cout << oo2 << "====>" << &oo2 << endl; ++oo2; cout << oo2 << "====>" << &oo2 << endl; return 0; }
- 运行结果
14
====>004FFB44
后增量
15
====>004FFB44
前增量
16
====>004FFB44
3、插入运算符<<重载
- 参考以上代码
friend ostream& operator<<(ostream& out, Obj2& o2) { cout << o2.num <<endl; return out; }
- ps:
- 声明为友元类的原因:方便访问类的私有或保护成员属性
- 当然也可以不声明为友元,但是非友元需要通过public方法,访问private、protected;
4、转换运算符()的重载
类似于我们平时的
(int)5.02
-->将5.02强制转换成**int**
类型 , 当我们想要强行转换类的类型的时候,就会用到转换运算符的重载了。
- 转换运算符的声明形式
operator 类型名 ();
- 他没有返回类型,因为类型名就代表了他的返回类型,如果再写返回类型,则显得有点多余
#include<iostream> using namespace std; class RMB { private: unsigned int yuan, jiao; public: RMB( double val = 0) { yuan = (unsigned int)val ; jiao = (unsigned int)(val*100) % 100; } /// 转换运算符-->强制类型转换成double operator double() { return yuan + (double)(jiao / 100); } friend ostream& operator<<(ostream& out,RMB &r) { cout << "===========\r\n"; cout << "元:"<<r.yuan <<"\r\n角:"<< r.jiao << endl; return out; } }; int main() { RMB r(5.21); cout << r; return 0; }
- 输出结果
===========
元:5
角:21
- 这里有个小坑,当我们不声明为友元的时候(运行的时候注意看输出)
#include<iostream> using namespace std; class RMB { private: unsigned int yuan, jiao; public: RMB( double val = 0) { yuan = (unsigned int)val ; jiao = (unsigned int)(val*100) % 100; } /// 转换运算符-->强制类型转换成double operator double() { return yuan + (double)(jiao / 100); } ostream& operator<<(ostream& out) { cout << "===========\r\n"; cout << "元:"<<this->yuan <<"\r\n角:"<< this->jiao << endl; return out; } }; int main() { RMB r(5.21); cout << r; return 0; }
- 输出结果为
5
- 通过调试可以知道,当程序执行到
cout<<r
的时候,程序跳转到了 operator double() { return yuan + (double)(jiao / 100); }
这也是为什么输出5的原因。
- 至于为什么呢?
- –》主要涉及到了运算符优先级的问题
强制类型转换的优先级大于插入运算符
5、赋值运算符的重载
类似于:
RMB r(5.1); EN e; e=r; // c++是不允许这样操作的
要使e=r成立,我们就可以人为地进行赋值运算符的重载
#include<iostream> using namespace std; class EN; class RMB { private: int yuan, jiao; public: RMB(double val = 0.0) { yuan = (int)val; jiao = ((int)(val * 100))% 100; } double getMoney() { return yuan + (double)jiao / 100; } }; class EN { private: double meiyuan; public: EN(double val = 0) :meiyuan(val) {}; EN& operator=(RMB& rmb) { this->meiyuan = rmb.getMoney(); return *this; } void display() { cout << meiyuan << endl; } }; int main() { RMB r(8.67); EN e; e.display(); e = r; e.display(); }
- 输出结果
0
8.67
- 注意点
double getMoney() { return yuan + (double)jiao / 100; }
如果写成
double getMoney() { return yuan + (double)(jiao / 100); }
的话,则不会得到第二个8.67;
- 原因是因为先对
jiao
进行类型转换在/100
, 可以得到0.67
; - 对
(jiao/100)
进行类型转换的话就可会得到0
THE END !
感谢您的耐心阅读
欢迎指正错误