算术运算符重载
算术运算符重载分为:+ , - , * , / , % , += , -= , *= , /= …
这篇文章主要以 加号运算符重载 为例子介绍,其他的重载方式都是一样的。
为什么要使用加号运算符重载(operator)
C/C++的运算符,仅限于基本数据类型的运算。
那么问题来了,怎么使一头牛和一只羊类型的数据相加呢?
一头牛 + 一头马 = ?(牛马神兽?)
一个圆 + 一个圆 = ? (想要变成一个更大的圆)
一头牛 – 一只羊 = ? (想要变成4只羊,原始的以物易物:1头牛价值5只羊)
解决方案:
使用运算符重载
运算符重载的两种形式
一、使用成员函数重载运算符
二、使用非成员函数【友元函数】重载运算符
使用operator关键字实现运算符重载
下面示例以 + 号作为例子
其他运算符 - * / 等都是一样的
使用成员函数重载运算符
需求:
使用运算符重载,来实现:
一头牛 + 一只羊 = ?
一头牛 + 一头牛 = ?
假设:
一斤猪肉 = 两斤牛肉
一斤猪肉 = 三斤羊肉
代码示例前讲解:
第一:定义一头牛的类,实现定义函数重载运算符
第二:定义羊类
第三:定义猪类
第四:main函数实现
代码实例:
第一:定义牛类Cow.h
#pragma once
class Sheep;
class Pig;
class Cow {
public:
Cow(float weigth = 0.0);
// 使用运算符重载,来实现:一头牛 + 一只羊 = ?
// 一头牛 + 一头牛 = ?
Pig operator+(const Sheep &sheep); // 牛+羊
Pig operator+(const Cow &cow); // 牛+牛
private:
float weigth; // 牛的体重
};
Cow.cpp
#include "Cow.h"
#include "Pig.h"
#include "Sheep.h"
Cow::Cow(float weigth) {
this->weigth = weigth;
}
Pig Cow::operator+(const Sheep &sheep) {
// 牛肉 * 2 + // 羊肉 * 3
float ret = this->weigth * 2 + sheep.getWeigth() * 3;
// 返回前转换为Pig类型
return Pig(ret);
}
Pig Cow::operator+(const Cow &cow) {
// (牛 + 牛)* 2
float ret = (this->weigth + cow.weigth) * 2;
// 返回前转换为Pig类型
return Pig(ret);
}
第二:定义羊类Sheep.h
#pragma once
class Sheep {
public:
Sheep(float weigth = 0.0);
float getWeigth() const;
private:
float weigth; // 羊的体重
};
Sheep.cpp
#include "Sheep.h"
Sheep::Sheep(float weigth) {
this->weigth = weigth;
}
float Sheep::getWeigth() const {
return weigth;
}
第三:定义猪类Pig.h
#pragma once
#include <string>
class Pig {
public:
Pig(float weigth = 0.0);
std::string description() const;
private:
float weigth;
};
Pig.cpp
#include <sstream>
#include "Pig.h"
Pig::Pig(float weigth) {
this->weigth = weigth;
}
std::string Pig::description() const {
std::stringstream ret;
ret << "weigth = " << weigth << "斤猪肉" << std::endl;
return ret.str();
}
第四:main函数实现
#include <iostream>
#include "Pig.h"
#include "Cow.h"
#include "Sheep.h"
using namespace std;
int main(void) {
Cow c1(100); // 定义一头牛一百斤
Cow c2(200); // 定义一头牛两百斤
// 调用c1.operator+(c2);
//相当于:Pig p = c1.operator+(c2);
Pig p = c1 + c2;
cout << p.description();
Sheep s(100); // 定义一只羊一百斤
// 相当于: p = c1.operator+(s);
p = c1 + s;
cout << p.description();
system("pause");
return 0;
}
运行截图:
使用非成员函数【友元函数】重载运算符
和友元函数的定义的方法一样的
不知道友元函数的朋友,请看我另一篇文章:C++ 友元https://blog.youkuaiyun.com/cpp_learner/article/details/104193181
需求:
使用友元函数实现:
一头牛+一头牛
一头牛+一头羊
一头羊+一头牛
注意:牛+羊 和 羊+牛 是不一样的,会调用不一样的重载运算符函数
代码实例:
Cow.h
#pragma once
class Sheep;
class Pig;
class Cow {
public:
Cow(float weigth = 0.0);
private:
float weigth; // 牛的体重
// 声明为友元函数
friend Pig operator+(Cow &c1, Cow &c2);
friend Pig operator+(Cow &cow, Sheep &sheep);
friend Pig operator+(Sheep &sheep, Cow &cow);
};
Cow.cpp
#include "Cow.h"
#include "Pig.h"
#include "Sheep.h"
Cow::Cow(float weigth) {
this->weigth = weigth;
}
Sheep.h
#pragma once
class Pig;
class Cow;
class Sheep {
public:
Sheep(float weigth = 0.0);
float getWeigth() const;
private:
float weigth; // 羊的体重
// 声明为友元函数
friend Pig operator+(Cow &cow, Sheep &sheep);
friend Pig operator+(Sheep &sheep, Cow &cow);
};
Sheep.cpp
#include "Sheep.h"
float Sheep::getWeigth() const {
return weigth;
}
Pig.h
#pragma once
#include <string>
class Pig {
public:
Pig(float weigth = 0.0);
std::string description() const;
private:
float weigth;
};
Pig.cpp
#include <sstream>
#include "Pig.h"
Pig::Pig(float weigth) {
this->weigth = weigth;
}
std::string Pig::description() const {
std::stringstream ret;
ret << "weigth = " << weigth << "斤猪肉" << std::endl;
return ret.str();
}
main函数实现
#include <iostream>
#include "Pig.h"
#include "Cow.h"
#include "Sheep.h"
using namespace std;
// 牛+牛
Pig operator+(Cow &c1, Cow &c2) {
int ret = (c1.weigth + c2.weigth) * 2;
return Pig(ret);
}
// 牛+羊
Pig operator+(Cow &cow, Sheep &sheep) {
int ret = cow.weigth*2 + sheep.weigth*3;
return Pig(ret);
}
// 羊+牛
Pig operator+(Sheep &sheep, Cow &cow) {
int ret = sheep.weigth*3 + cow.weigth*2;
return Pig(ret);
}
int main(void) {
Cow c1(100);
Cow c2(200);
Pig p = c1 + c2;
cout << p.description();
Sheep s(100);
p = s + c1;
cout << p.description();
system("pause");
return 0;
}
运行截图:
两种方式的区别
区别:
- 使用成员函数来实现运算符重载时,少写一个参数,因为第一个参数就是this指针。
两种方式的选择:
- 一般情况下,单目运算符重载,使用成员函数进行重载更方便(不用写参数)
- 一般情况下,双目运算符重载,使用友元函数更直观
方便实现a+b和b+a相同的效果,成员函数方式无法实现。
例如: 100 + cow; 只能通过友元函数来实现
cow +100; 友元函数和成员函数都可以实现
特殊情况:
(1) = () [ ] -> 不能重载为类的友元函数!!!(否则可能和C++的其他规则矛盾),只能使用成员函数形式进行重载。
(2)如果运算符的第一个操作数要求使用隐式类型转换,则必须为友元函数(成员函数方式的第一个参数是this指针)
注意:
同一个运算符重载, 不能同时使用两种方式来重载,会导致编译器不知道选择哪一个(二义性)
运算符重载的禁区和规则
- 为了防止对标准类型进行运算符重载,C++规定重载运算符的操作对象至少有一个不是标准类型,而是用户自定义的类型;
比如不能重载 1+2
但是可以重载 cow + 2 和 2 + cow // cow是自定义的对象
2.不能改变原运算符的语法规则, 比如不能把双目运算符重载为单目运算
-
不能改变原运算符的优先级
-
不能创建新的运算符,比如 operator**就是非法的, operator*是可以的
-
不能对以下这四种运算符,使用友元函数进行重载【 = 赋值运算符,()函数调用运算符,[ ]下标运算符,->通过指针访问类成员】
-
不能对禁止重载的运算符进行重载
不能被重载的运算符
*** | *** |
---|---|
成员函数 | . |
域运算 | :: |
内存长度运算 | sizeof |
三目运算 | ? : |
预处理 | # |
可以被重载的运算符
*** | *** |
---|---|
双目运算符 | + - * / % |
关系运算符 | == != < <= > >= |
逻辑运算符 | &&与 或 !非 |
单目运算符 | +(正号) -(负号) *(指针) &(取地址) ++ – |
位运算 | & 或 ~ ^ <<(左移) >>(右移) |
赋值运算符 | = += -= *= /= %= &= 或等 ^= <<= >>= |
内存分配 | new delete new[ ] delete[ ] |
其他 | ( ) 函数调用 -> 成员访问 [ ]下标 ,逗号 |
注意:
表格中逻辑运算符中 “或” 是 ||
赋值运算符中 “或等” 是 |=
总结:
算术运算符重载,也许用得不多,但也是一个挺有用的知识点。如果有需求是两个对象之间进行算术运算符操作,就可以使用到它!