【全文大纲】 : https://blog.youkuaiyun.com/Engineer_LU/article/details/135149485
前言
- 有时候为了更方便对象内存交互,因此诞生了运算符重载,可以让对象的内存之间进行加减乘除等运算,以下深入浅出描述C++运算符重载
- 运算符重载的本质是函数
1 . 运算符重载-限制
- 可重载的运算符 :
+ | - | * | / | % | ^ | & |
---|---|---|---|---|---|---|
| | ~ | ! | = | < | > | += |
-= | *= | /= | %= | ^= | &= | = |
<< | >> | >>= | <<= | == | != | <= |
>= | && | || | ++ | – | ->* | ‘ |
-> | [] | () | new | delete | new[] | delete[] |
- 不可重载的运算符 :
. | :: | .* | ?: | sizeof |
---|
其中下面四个运算符不可在全局函数中重载
= | [] | -> | () |
---|
其中下面这个运算符重载由于其左值必须为osteam类,因此只能重载为友元函数
<< |
---|
- 小结 :C++大部分运算符可以重载
2 . 运算符重载-差异
运算符重载前 | 运算符重载后 | |
---|---|---|
优先级 | 不变 | 不变 |
结合性 | 不变 | 不变 |
语意 | 不变 | 改变 |
- 小结 :重载只会让语意改变,其余不变
3 . 运算符重载-语法
成员函数 | 返回值类型 类名 :: operator 运算符 ( 参数列表 ){ } |
---|---|
全局函数 | 返回值类型 operator opa( 参数列表 ){ } |
- 小结 :两者语法基本一致
4 . 运算符重载-例子
1 . 在C++中,可以看到 cout << “Hello World”; 这样的写法如下图,为什么这样可以过编译呢?实际上 cout 是 ostream 类的对象,能在对象 cout 后面加上 << 是因为 ostream 这个类对 << 该运算符执行了重载的逻辑,而上述提到重载本质是函数,因此可以基于传入参数列表的内容与对象 cout 内的成员进行交互。
cout << "Hello World"; //编译后,cout内的 operator<<() 运算符重载函数被调用
2 . 下图是 成员运算符重载 与 全局运算符重载 的例子
人类a的年龄28岁,有150块,人类b的年龄22,有50块
通过全局运算符重载把这两个人的年龄相加得出50岁,金钱相加得出200块
通过成员运算符重载把这两个人的年龄相减得出6岁,金钱相减得出100块
- 全局运算符重载 的参数列表中引入两个对象参与运算,把两个具体的对象引入参与运算
- 成员运算符重载 的参数列表中引入一个对象参与运算,把引入的对象与运算符重载的 左值对象 参与运算 (隐式调用)
#include <iostream>
using namespace std;
class People {
public:
double age, money;
People():age(0),money(0) {}
People(double a, double m):age(a),money(m){}
People operator-(const People& f);
};
//重载运算符+ (重载为普通函数)
People operator+ (const People& a, const People& b)
{
return People(a.age + b.age, a.money + b.money); //返回一个临时对象
}
//重载运算符- (重载为成员函数)
People People::operator-(const People& p)
{
return People(age - p.age, money - p.money); //返回一个临时对象
}
int main()
{
People a(28, 150), b(22, 50), c;
c = a + b; //等同 c = operator+(a, b);
cout << c.age << c.money;//结果 50, 200
uint16_t age = (a - b).age; //等同a.operator-(b).age
uint16_t money = (a - b).money;
cout << age << money;//结果 6, 100
return 0;
}
3 . 既然运算符重载分为 成员运算符重载 与 全局运算符重载 ,全局运算符重载怎么访问类里的隐私数据,这里可以在类中把全局运算符重载声明为友元函数,这样全局运算符重载就可以访问类里的隐私数据,如下图,把 People operator+ (const People& a, const People& b) 声明为友元函数
【Q】这里可能有疑问,那把运算符重载函数全部塞到类里不就好了吗?
【A】上述提到有一些情况只能通过友元函数关联起来,例如 << 该运算符的特殊情况,因此勿要把运算符重载函数全部塞到类里
class People {
public:
double age, money;
People():age(0),money(0) {}
People(double a, double m):age(a),money(m){}
People operator-(const People& f);
friend People operator+(const People& f);
};
//重载运算符+ (重载为普通函数)
People operator+ (const People& a, const People& b)
{
return People(a.age + b.age, a.money + b.money); //返回一个临时对象
}
//重载运算符- (重载为成员函数)
People People::operator-(const People& p)
{
return People(age - p.age, money - p.money); //返回一个临时对象
}
4 . 运算符重载的妙处还有很多,如下图,运算符 = 两边的类型不一致时,又想让两边内存参与运算,这时候只需要把 = 重载, = 该运算符只能在成员函数中重载,因为如果是全局,那程序中很多类型赋值时检索,就会在赋予地址产生冲突,但若是在成员中重载,那仅仅相应的对象运算时才会重载,不会冲突
#include <iostream>
using namespace std;
class People {
public:
double age, money;
People():age(0),money(0) {}
People(double a, double m):age(a),money(m){}
uint16_t operator=(uint16_t m) {
return m + money;
}
};
int main()
{
People a(28, 150);
int memory = 10;
cout << (a = memory);
return 0;
}
5 . 运算符重载-触发
经过上述例子和规则描述,可以总结出当写了运算符重载后
- 当有全局运算符重载时就会检索相应运算符的 左值 右值,当左右都符合参数列表则执行运算符重载函数,
- 当有成员运算符重载时就会检索相应运算符的 左值,当左值的对象内有运算符重载触发检测,配对右值的类型,符合则执行运算符重载函数
6 . 总结
1 . 遵循原运算符语意扩展,即+运算,扩展后遵循+的逻辑交互内存
2 . 大部分运算符可以重载,小部分不可以(如上述描述)
3 . 个别运算符仅能在成员中重载
4 . 个别运算符仅能在全局中重载
5 . 运算符重载触发机制取决于是否属于全局/成员,参数列表是否符合
以上关于运算符重载的总结,谢谢观看。
技术交流QQ群 : 745662457
群内专注 - 问题答疑,项目外包,技术研究