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.不能改变运算符优先级,不能改变运算符的参数个数。

posted @ 2022-10-03 21:50  CodeMagicianT  阅读(137)  评论(0编辑  收藏  举报