28.加号运算符重载
1 运算符重载
1.1 运算符重载基本概念
运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。(运算符重载不能改变本来寓意,不能改变基础类型寓意)
运算符重载(operator overloading)只是一种”语法上的方便”,也就是它只是另一种函数调用的方式。
在c++中,可以定义一个处理类的新运算符。这种定义很像一个普通的函数定义,只是函数的名字由关键字operator及其紧跟的运算符组成。差别仅此而已。它像任何其他函数一样也是一个函数,当编译器遇到适当的模式时,就会调用这个函数。
语法:
定义重载的运算符就像定义函数,只是该函数的名字是operator@,这里的@代表了被重载的运算符。函数的参数中参数个数取决于两个因素。
运算符是一元(一个参数)的还是二元(两个参数);
运算符被定义为全局函数(对于一元是一个参数,对于二元是两个参数)还是成员函数(对于一元没有参数,对于二元是一个参数-此时该类的对象用作左耳参数)
[两个极端]
有些人很容易滥用运算符重载。它确实是一个有趣的工具。但是应该注意,它仅仅是一种语法上的方便而已,是另外一种函数调用的方式。从这个角度来看,只有在能使涉及类的代码更易写,尤其是更易读时(请记住,读代码的机会比我们写代码多多了)才有理由重载运算符。如果不是这样,就改用其他更易用,更易读的方式。
对于运算符重载,另外一个常见的反应是恐慌:突然之间,C运算符的含义变得不同寻常了,一切都变了,所有C代码的功能都要改变!并非如此,对于内置的数据类型的表示总的所有运算符是不可能改变的。我们不能重载如下的运算符改变其行为。
1 + 4;
1.2运算符重载碰上友元函数
友元函数是一个全局函数,和我们上例写的全局函数类似,只是友元函数可以访问某个类私有数据。
案例: 重载左移操作符(<<),使得cout可以输出对象。
class Person{
friend ostream& operator<<(ostream& os, Person& person);
public:
Person(int id,int age){
mID = id;
mAge = age;
}
private:
int mID;
int mAge;
};
ostream& operator<<(ostream& os, Person& person){
os << "ID:" << person.mID << " Age:" << person.mAge;
return os;
}
int main(){
Person person(1001, 30);
//cout << person; //cout.operator+(person)
cout << person << " | " << endl;
return EXIT_SUCCESS;
}
1.3可重载的运算符
几乎C中所有的运算符都可以重载,但运算符重载的使用时相当受限制的。特别是不能使用C中当前没有意义的运算符(例如用**求幂)不能改变运算符优先级,不能改变运算符的参数个数。这样的限制有意义,否则,所有这些行为产生的运算符只会混淆而不是澄清寓语意。
除了赋值号(=)外,基类中被重载的操作符都将被派生类继承。
特殊运算符
●=,[], () 和 -> 操作符只能通过成员函数进行重载
●<< 和 >> 操作符最好通过友元函数进行重载
● 不要重载 && 和 || 操作符,因为无法实现短路规则
常规建议
2.视频内容
程序1:
#pragma warning(disable:4996)
//2022年10月3日21:14:08
#include <iostream>
using namespace std;
class Maker
{
public:
Maker(int id, int age)
{
this->id = id;
this->age = age;
}
public:
int id;
int age;
};
//全局方式
Maker operator+(Maker &p1, Maker &p2)
{
Maker temp( p1.id + p2.id, p1.age + p2.age );
return temp;
}
void test01()
{
Maker m1( 1, 20 );
Maker m2( 2, 22 );
Maker m3 = m1 + m2;
cout << "id: " << m3.id << " age: " << m3.age << endl;
}
int main()
{
test01();
system( "pause" );
return EXIT_SUCCESS;
}
输出结果:
id: 3 age: 42
请按任意键继续. . .
程序2:
#pragma warning(disable:4996)
//2022年10月3日21:14:08
#include <iostream>
using namespace std;
class Maker
{
public:
Maker(int id, int age)
{
this->id = id;
this->age = age;
}
//写成成员函数,那么只需要一个参数,这个参数是加号的右边
//Maker operator+(Maker &m2)
//{
// Maker temp( this->id + p2.id, this->age + p2.age );
// return temp;
//}
public:
int id;
int age;
};
//全局方式//2.编译器会调用这个函数
Maker operator+(Maker &p1, Maker &p2)//3.编译器检查参数是否对应,第一个参数是加号的左边,第二个参数是加号的右边
{
Maker temp( p1.id + p2.id, p1.age + p2.age );
return temp;
}
void test01()
{
Maker m1( 1, 20 );
Maker m2( 2, 22 );
//+号也叫双目运算符
Maker m3 = m1 + m2;//1.编译器看到两个对象相加,那么编译器会去找有没有叫operator+的函数
cout << "id: " << m3.id << " age: " << m3.age << endl;
}
int main()
{
test01();
system( "pause" );
return EXIT_SUCCESS;
}
输出结果:
id: 3 age: 42
请按任意键继续. . .
程序3:
#pragma warning(disable:4996)
//2022年10月3日21:14:08
#include <iostream>
using namespace std;
class Maker
{
public:
Maker(int id, int age)
{
this->id = id;
this->age = age;
}
/*写成成员函数,那么只需要一个参数,这个参数是加号的右边*/
Maker operator+(Maker &p2)
{
Maker temp( this->id + p2.id, this->age + p2.age );
return temp;
}
public:
int id;
int age;
};
//全局方式//2.编译器会调用这个函数
//Maker operator+(Maker &p1, Maker &p2)//3.编译器检查参数是否对应,第一个参数是加号的左边,第二个参数是加号的右边
//{
// Maker temp( p1.id + p2.id, p1.age + p2.age );
//
// return temp;
//}
void test01()
{
Maker m1( 1, 20 );
Maker m2( 2, 22 );
//+号也叫双目运算符
Maker m3 = m1 + m2;//1.编译器看到两个对象相加,那么编译器会去找有没有叫operator+的函数
cout << "id: " << m3.id << " age: " << m3.age << endl;
Maker m4 = m1 + m2 + m3;
cout << "id: " << m4.id << " age: " << m4.age << endl;
}
int main()
{
test01();
system( "pause" );
return EXIT_SUCCESS;
}
输出结果:
id: 3 age: 42
id: 6 age: 84
请按任意键继续. . .
程序4:
#pragma warning(disable:4996)
//2022年10月4日22:08:02
#include <iostream>
using namespace std;
class Maker
{
public:
Maker( int id, int age )
{
this->id = id;
this->age = age;
}
public:
int id;
int age;
};
class Student
{
public:
Student()
{
mid = 0;
}
Student( int id )
{
mid = id;
}
public:
int mid;
};
Student operator+( Maker &m, Student &s )
{
Student tmp( m.id + s.mid );
return tmp;
}
void test()
{
Maker m1( 1, 18 );
Student s1( 2 );
m1 + s1;
}
int main()
{
test();
system( "pause" );
return EXIT_SUCCESS;
}
3.运算符重载的概念(重点)
1.运算符重载,就是对已有的运算符重新进行定义,[赋予]其另一种功能,以适应不同的数据类型。
2.运算符重载的目的是让语法更加简洁
3.运算符重载不能改变本来寓意,不能改变基础类型寓意
4.运算符重载的本质是另一种函数调用(是编译器去调用)
5.这个函数同一的名字叫operator
6.重载函数可以写成全局或成员函数
7.重载函数如果写成全局的,那么双目运算符左边的是第一个参数,右边是第二个参数
8.重载函数如果写成成员函数,那么双目运算符的左边是this,右边是第一个参数
9.不能改变运算符优先级,不能改变运算符的参数个数。