C++加号运算符重载——2022年11月23日cpp学习日志

4.5 运算符重载

对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型

4.5.1 加号运算符重载

作用:实现两个自定义类型(如Person p1Person p2)相加的运算

对于内置的数据类型,编译器知道如何进行运算,如下:

int a = 10;
int b = 10;
int c = a+b;

但是对于以下运算,编译器不知道如何对自定义数据类型进行相加:

class Person
{
public:
    int m_A;
    int m_B;
};


void test01()
{
    Person p1;
    p1.m_A = 10;
    p1.m_B = 10;

    Person p2;
    p2.m_A = 10;
    p2.m_B = 10;

    // 想创建第三个人,让第三个人的m_A和m_B属性等于p1和p2的m_A和m_B的和
    Person p3 = p1 + p2;	// 编译器此时不知道要完成我们程序员想要实现的这种操作,会报错:
    						// 		没有与这些操作数匹配的"+"运算符,操作数类型为:Person + Person
}

(先抛开加号运算符重载的知识)我们可以自己定义一个成员函数(即需要通过p1p2这些对象来调用的函数)来实现我们想要的相加功能:

// 在Person类内定义一个成员函数,实现我们想要的相加功能
Person PersonAddPerson(Person &p)
{
    Person tmp;
    tmp.m_A = this->m_A + p.m_A;
    tmp.m_B = this->m_B + p.m_B;
    return tmp;	// 调用拷贝构造函数,创建一个拷贝体作为返回值
}

这样我们可以实现相加功能:

Person p3 = p1.PersonAddPerson(p2);

但是每个程序员不一定都起名PersonAddPerson(),这样函数名就会因人而异,于是编译器就说:“不如我来起个名,大家都统一用我的,并且我能承诺提供一个简易的"+"就让你们能调用这个函数!这个通用的名称就叫operator+,也就是说我们上面定义的成员函数统一改成:

Person operator+(Person &p)
{
    Person tmp;
    tmp.m_A = this->m_A + p.m_A;
    tmp.m_B = this->m_B + p.m_B;
    return tmp;	
}

这个时候如果我们要来调用这个函数,正常的调用方式就是这样的:

Person p3 = p1.operator+(p2);	// 本质的调用方式

考虑到编译器的承诺,我们可以简化上面的调用方式为:

Person p3 = p1 + p2;			// 简化的调用方式

也就是说当我们用了编译器提供的函数名:operator+之后,我们就可以实现上述的简化的函数调用方式,此时我们再来实现我们开始时想要实现的运算:

class Person
{
public:
    int m_A;
    int m_B;

    Person operator+(Person& p)	// 成员函数实现运算符重载
    {
        Person tmp;
        tmp.m_A = this->m_A + p.m_A;
        tmp.m_B = this->m_B + p.m_B;
        return tmp;
    }
};

void test01()
{
    Person p1;
    p1.m_A = 10;
    p1.m_B = 10;

    Person p2;
    p2.m_A = 10;
    p2.m_B = 10;

/*****************************************开始时我们想要实现的运算*****************************************/
    // 想创建第三个人,让第三个人的m_A和m_B属性等于p1和p2的m_A和m_B的和
    Person p3 = p1 + p2;	// 编译器此时就不会报错了
/******************************************************************************************************/
    cout << p3.m_A << p3.m_B << endl;	// 2020,预期的输出✔
    
    //Person p4 = p1.operator+(p2);		// 这行可以直接使用,它是第28行代码的本质调用函数,该行代码的简化调用就是
    									// 第28行代码
}

此时编译器就不会报错了!以上即成员函数实现"+"运算符重载

那么我们还可以通过全局函数来实现运算符重载:

// 在Person类外定义应该全局函数,实现我们想要的相加功能
Person operator+(Person &p1, Person &p2)
{
    Person tmp;
    tmp.m_A = p1.m_A + p2.m_A;
    tmp.m_B = p1.m_B + p2.m_B;
    return tmp;
}

这个时候如果我们要来调用这个函数,正常的调用方式就是这样的:

Person p3 = operator+(p1, p2);	// 本质的调用方式

我们可以同样简化上面的调用方式为:

Person p3 = p1 + p2;			// 简化的调用方式

此时我们也同样可以完成我们开始时想要实现的运算

class Person
{
public:
    int m_A;
    int m_B;
};

Person operator+(Person &p1, Person &p2)	// 全局函数实现运算符重载
{
    Person tmp;
    tmp.m_A = p1.m_A + p2.m_A;
    tmp.m_B = p1.m_B + p2.m_B;
    return tmp;
}

void test01()
{
    Person p1;
    p1.m_A = 10;
    p1.m_B = 10;

    Person p2;
    p2.m_A = 10;
    p2.m_B = 10;

    //Person p3 = operator+(p1, p2);
/*****************************************开始时我们想要实现的运算*****************************************/
    // 想创建第三个人,让第三个人的m_A和m_B属性等于p1和p2的m_A和m_B的和
    Person p3 = p1 + p2;	// 编译器此时就不会报错了 
/******************************************************************************************************/
    cout << p3.m_A << p3.m_B << endl;	// 2020,预期的输出✔
    
    //Person p3 = operator+(p1, p2);	// 这行可以直接使用,它是第29行代码的本质调用函数,该行代码的简化调用就是
    									// 第29行代码
}

以上即完成了全局函数实现"+"运算符重载!

4.5.1.1 成员函数和全局函数的调用小区别

我们还可以注意成员函数和全局函数的调用区别:

  • 成员函数:
// 在Person类内定义一个成员函数,实现我们想要的相加功能
Person PersonAddPerson(Person &p)
{
    Person tmp;
    tmp.m_A = this->m_A + p.m_A;
    tmp.m_B = this->m_B + p.m_B;
    return tmp;	// 调用拷贝构造函数,创建一个拷贝体作为返回值
}
  • 全局函数:
// 在Person类外定义应该全局函数,实现我们想要的相加功能
Person operator+(Person &p1, Person &p2)
{
    Person tmp;
    tmp.m_A = p1.m_A + p2.m_A;
    tmp.m_B = p1.m_B + p2.m_B;
    return tmp;
}

成员函数调用时是这样的:

p1.operator+(p2);

即通过一个对象p1调用函数,然后传入另一个对象p2作为实参

而全局函数调用是这样的:

operator+(p1, p2);

即对象p1和对象p2都作为函数实参

4.5.1.2 运算符重载也可以发生函数重载

函数名相同,传入的参数类型不同实现重载。

目的:复用operator+这个函数名

例如我们如果要实现以下代码

Person p3 = p1 + 20;	// 此时编译器会报错:
						//		没有与这些操作数匹配的"+"运算符,操作数类型为:Person + int 
  • 此时我们若要通过成员函数重载来实现运算符重载,则Person类定义如下:
class Person
{
public:
    int m_A;
    int m_B;

    Person operator+(Person& p)	// 运算符重载
    {
        Person tmp;
        tmp.m_A = this->m_A + p.m_A;
        tmp.m_B = this->m_B + p.m_B;
        return tmp;
    }

    Person operator+(int num)	// 成员函数重载实现运算符重载
    {
        Person tmp;
        tmp.m_A = this->m_A + num;
        tmp.m_B = this->m_B + num;
        return tmp;
    }
};

然后在test02()中即可完成Person + int的操作且不报错:

void test02()
{
    Person p1;
    p1.m_A = 10;
    p1.m_B = 10;

    Person p2;
    p2.m_A = 10;
    p2.m_B = 10;

    Person p4 = p1 + 20;
    cout << p4.m_A << p4.m_B << endl;	// 3030,预期的输出✔
}
  • 全局函数重载实现运算符重载
class Person
{
public:
    int m_A;
    int m_B;
};

Person operator+(Person &p1, Person &p2)// 运算符重载
{
    Person tmp;
    tmp.m_A = p1.m_A + p2.m_A;
    tmp.m_B = p1.m_B + p2.m_B;
    return tmp;
}

Person operator+(Person& p1, int num)	// 全局函数重载实现运算符重载
{
    Person tmp;
    tmp.m_A = p1.m_A + num;
    tmp.m_B = p1.m_B + num;
    return tmp;
}

同样的可以在test02()中完成Person + int的操作且不报错。

**注意:**全局函数重载实现运算符重载时,operator+()中的形参类型不可调换,如下:

Person operator+(int num, Person& p1)	
{
    Person tmp;
    tmp.m_A = p1.m_A + num;
    tmp.m_B = p1.m_B + num;
    return tmp;
}

调换后当我在test02()中调用以下代码时就会报错:

Person p4 = p1 + 20;	// 没有与这些操作数匹配的 "+" 运算符:Person + int

此时只有调换参数顺序才能正常执行test02(),因为此时编译器只认int + Person的’‘+’'操作:

Person p4 = 20 + p1;	// 调换参数顺序,int + Person

另外还要注意:

  1. 对于内置的数据类型(如int,double这些)的表达式的运算是不可能改变的,改变的只能是我们自定义的数据类型
  2. 不要滥用运算符重载(即不要在写operator+()函数时,函数内实现的却是"-"(减)操作,这种情况编译器可以编译和运行,但不符合我们的规范!!!这叫滥用)

以上内容为2022年11月23日,我的C++加号运算符重载学习日志,内容总结整理来自这位老师的视频:39 类和对象-C++运算符重载-加号运算符重载

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值