☘️ 前言:
⛪️ 个人主页:Jemery-An
个人介绍:业余编码,若有不对希望大家不吝赐教,相互学习,共同讨论,一起进步
☀️ 摘抄好句: 追光的人,他终将会光芒万丈
文章介绍: 本文讲解了运算符重载基本使用方法与概念,希望阅读的人能有所收获吧!
一、官方解释:运算符重载将重载的概念扩展到运算符上,允许赋予C++运算符多种含义
二、平时我们 简单的 +,-,*,/,||,&&,!这类运算符只能用于对基本数据类型的运算,但是不能用于 类对象之间运算
那我们想要实现两个对象之间运算呢?比如相加两个对象
三、C++提供了运算符重载机制,通过重载运算符,赋予其运算符另一种功能,不再局限于基本数据类型的运算,所以就能实现两个对象相加这样的需求
四、运算符重载其目的就是为了让运算符也能操作类对象。
要重载运算符,需使用被称为运算符函数的特殊函数形式。运算符函数的格式如下
返回值类型 operator 运算符(agrgument-list)
{
.....
}
例如:
obj operator +(); //重载的是+运算符
obj operator -(); //重载的是-运算符
运算符必须是有效的C++运算符,不能虚构一个新的运算符。例如不能有operator @();这样的函数运算符,因为C++中没有这样的运算符
一、如果我们想对两个人的数学成绩和英语成绩进行相加,其就是为了实现:P3=P1+P2
不使用重载运算符:我们可以通过自己写成员函数或定义全局函数的方式来实现两个对象相加属性后返回新对象
代码如下:
#include
using namespace std;
class Person {
public:
Person() {
};
Person(int a, int b) {
this->math = a;
this->eng = b;
}
Person sum(Person& p1) {//成员函数
Person temp;
temp.eng = this->eng + p1.eng;
temp.math = this->math + p1.math;
return temp;
}
public:
int math=0, eng=0;
};
Person sum(Person& p1,Person& p2) { //全局函数
Person temp;
temp.eng = p2.eng + p1.eng;
temp.math =p2.math + p1.math;
return temp;
}
int main() {
Person p1(90, 98);
Person p2(100, 90);
Person p3;
//p3 = p1.sum(p2); 局部函数
p3 = sum(p1, p2);
cout << p3.eng << endl << p3.math << endl;
return 0;
}
小知识1: 参数为引用类型的好处
来看sum函数不管是成员函数还是全局函数,注意参数都是引用,但返回类型却不是引用。将参数作为引用的目的是为了提高效率。
如果按值传递Person对象,代码的功能将相同,但传递引用,速度将更快,使用的内存将更少,在编码过程中我们要巧妙的使用引用!
小知识2:为什么返回类型不能用引用
如果返回类型为Person & 引用的则是temp对象,由于temp对象是局部对象在函数结束时将被删除,因此,引用将指向一个不存在的对象。
如果使用返回类型Person就意味着在删除sum之前构造它的拷贝,调用函数将得到该拷贝。
使用重载运算符:
运算符可以被重载为成员函数,也可以被重载为全局函数,我们一般倾向于把运算符函数定义为成员函数,这样能清晰的看出与类的关系
代码如下:
#include
using namespace std;
class Person {
public:
Person() {
};
Person(int a, int b) {
this->math = a;
this->eng = b;
}
Person operator+(Person& p1) { //成员函数
Person temp;
temp.eng = this->eng + p1.eng;
temp.math = this->math + p1.math;
return temp;
}
public:
int math,eng;
};
Person operator+(Person & p1, Person & p2) { //全局函数
Person temp;
temp.eng = p2.eng + p1.eng;
temp.math =p2.math + p1.math;
return temp;
} 对于一个类的运算,相同运算符重载的函数,全局和成员只能存在其中一个
int main() {
Person p1(100, 90);
Person p2(100, 80);
Person p3 = p1 + p2;
cout << p3.eng << endl << p3.math << endl;
return 0;
}
如果仔细查看上面代码,其实不难看出我们把对当前对象运算的细节都写在了运算符函数方法体中
Person operator+(Person& p1) { //成员函数
Person temp;
temp.eng = this->eng + p1.eng;
temp.math = this->math + p1.math;
return temp;
}
一、上面代码中Person类,为它定义了一个operator +()的运算函数,以重载+运算符,以便能够将两个Person对象的分数相加,p1与p2都是都是类Person的对象,所以可以编写如下的等式
Person p3;
p3 = p1 + p2;
p3 = p1.operator+(p2);编译器转换替换后
二、编译器发现操作数即两个对象都是Person类对象因此使用相应的运算符函数替换上述运算符
三、然后该函数将隐式的使用p1,因为p1作为对象调用函数,而显式的使用p2,因为p2被作为参数传递,来计算总和并返回这个值
四、如果对两个对象直接进行运算并且重载了运算符,那么编译器会自动识别匹配相应的运算符函数替换运算,可以使用简单的+运算符表示法即 obj = obj1 + obj2,不用使用笨拙的函数表示法
例如:p1,p2,p3 都是Person的对象,可以这样做吗?
P5 = p1 + p2 + p3 ;
由于+是从左向右结合的运算符,因此上述语句首先被转化成下面 这样:
p5 = p1.operator(p2 + p3);
然后函数参数本身被转换成一个函数调用,结果如下:
p5 = p1.operator(p2.operator+(p3));
上述语句均是合法的
cout是一个ostream对象它是智能的能够识别所有C++基本类型。这是因为对于每种基本类型,ostream类声明中都包含了相应的重载的operator()定义。
也就是说,一个方法定义使用int,一个定义使用double参数,等等。因此要使cout能够识别Person对象,一种方法是将一个新的函数运算符定义添加到ostream类声明中,但修改ostream是个危险的主意,这样做会在标准接口上浪费时间。
相反,通过Person类声明来让Person类知道怎么使用cout。
class Person{
public:
//利用成员函数重载 左移运算符 p.operator<<(p)
void operator<<(Person &p){
//不能这样写利用成员函数重载<<运算符
}
}
全局函数重载左移运算符
#include
using namespace std;
class Person {
//添加全局重载<<运算符函数为友元函数就可以访问Person类中的私有成员属性
friend ostream& operator <<(ostream& out, Person& p);
public:
Person() {};
Person(int a, int b) {
this->math = a;
this->eng = b;
}
//成员函数实现重载+运算符
Person operator+(Person& p1) {
Person temp;
temp.eng = this->eng + p1.eng;
temp.math = this->math + p1.math;
return temp;
}
private:
int math,eng;
};
//全局函数实现重载左移运算符
ostream& operator <<(ostream &out,Person &p) {
cout << "p.eng=" << p.eng << "\tp.math=" << p.math << endl;
return out;
}
int main() {
//实例化一个对象
Person p(100,90);
//这样就可以直接输出p对象了
cout << p;
system("pause");
return 0;
}
+ | - | * | / | % | ^ |
---|---|---|---|---|---|
& | | | ~= | ! | = | < |
> | += | -= | *= | /= | %= |
^= | &= | |= | << | >> | >>= |
<<= | == | != | <= | >= | && |
|| | ++ | - - | , | ->* | -> |
() | [ ] | new | delete | new [ ] | delete[ ] |
对于很多运算符来说,可以选择使用成员函数或非成员函数来实现运算符重载。一般来说非成员函数应该是友元函数,这样它才能直接访问类的私有数据。