c++运算符重载,多对象相加报错

在学习运算符重载时,写了一个类外定义的加法重载,但在对多个对象相加时会报错,看了一些解释,最终发现是左值与右值的问题,解决方法是对两个参数加上const修饰

总体关于两条引用规则:

左值引用 只能引用左值

对左值引用加上const后,其也可以引用右值

下面进行详细解读,若有错误欢迎指正

代码如下:

//mian.cpp文件内容
#include<iostream>
#include"student.h"

//student.h文件内容
#ifndef __HEAD_H__
#define __HEAD_H__

#include<iostream>
class Student
{
	private:
		int id;
	public:
		Student(int x):id(x){}
		Student(){}
		int get_id();
		friend Student operator+(const Student &j,const Student &t);
//此处若将两个传参前的const去掉(包括cpp文件中的const),则在多个对象相加时报错:
//[错误] 无法绑定非常量左值引用(类型为 'Student&' )到右值,类型为 'Student'
//但在仅两个对象相加时正常编译
//又发现,仅将左边参数的const保留,编译也可以通过

		Student& operator=(Student &j)
		{
			Student x;
			this->id = j.id;
			return *this;
		}
};

#endif

//student.cpp文件内容
#include"student.h"

int Student::get_id()
{
	return this->id;
}

Student operator+(const Student &j,const Student &t)
{
	Student x;
	x.id = j.id + t.id;
	return x;
}


int main()
{
	Student a(20),b(30),c(10);
	Student d = a+b+c;
	std::cout << d.get_id() << std::endl;
	return 0;
}

最后发现,这是一个关于左值、右值的问题。

首先介绍什么是左值与右值

在下面代码中我定义了一个整型变量,右边的10被赋值给左边的a

在绝大多数情况中,左值位于左边,右值位于右边,对于此例,是正确的。

而更深入的,我们可以先为左值右值下一个定义:左值是一个在内存中有位置的实际变量;而右值是一个字面量,没有储存空间,则也没有地址。

int a = 10;

左值可以被赋值,但是右值不能被赋值(变量a能赋值而10不能,其没有自己的位置)

而左值可以被赋值给左值,则此时就是前面所说右边的不全是右值,也可以为左值。

int i = a;

函数的返回值可以为左值或右值

为右值情况:

此时函数的返回值为一个临时值,可以被赋给一个左值

int get_x(int x)
{
    return x;
}

int a = get_x(10); 

为左值情况:

此时函数的返回值为一个引用,且返回的对象需为静态局部变量,否则对x的修改不会产生任何影响但也不会报错(笔者理解为,为返回值声明为引用后编译器会将该返回值当作可修改的左值?),若返回值不为引用则报错

#include<iostream>
using namespace std;

int& get_x()
{
	static int x = 10;
	cout << "x = " << x << endl;
	return x;
}

int main()
{
	get_x() = 20;    //输出:x = 10
	get_x();         //输出:x = 20
	return 0;
}

而对于函数调用,也有两种形式,一种是左值调用,一种是右值调用,见下面代码:

#include<iostream>
using namespace std;

void print(int value)
{
	cout << value << endl;
}

int main()
{
	int x = 10;
	print(x);	//左值调用:参数为左值,实际是将x的值赋给value
	print(10);	//右值调用:参数为右值,则是用该右值初始化了一个左值(value)
	return 0;
}

讲了这么多,终于要引入正题了,也就是我所遇到的问题:在重载加号运算符时,多个对象相加会报错。

首先有一个引用的规则:左值引用 只能引用左值

将刚刚的函数参数改为引用后,则右值调用会报错,因为在函数调用时,对value进行了初始化,将10赋给value,但因为value为一个左值引用,违反了上述的左值引用只能引用左值,则报错

#include<iostream>
using namespace std;

void print(int& value)
{
	cout << value << endl;
}

int main()
{
	print(10);	//此时使用右值调用会报错
    int x = 10;
    print(x);   //左值调用不报错
	return 0;
}

对于我所写的重载函数:

Student operator+(Student& j,Student& t)
{
	Student x;
	x.id = j.id + t.id;
	return x;
}

//重载函数 a + b 相当于operator+(a,b)

他的返回值是一个Student类的对象,但在执行完这个函数体后,这个对象的地址已经被释放,则实际上他的返回值为一个右值(我理解为任何函数体内初始化的非静态局部变量,作返回值时都为右值)而进行一次加法操作a = b + c时没有问题,因为此时加法返回一个右值,赋给左值a;而在进行多次加法b + c + d时,先执行b + c,返回一个右值,再执行这个右值与d的加法,此时出错,因为试图将一个右值赋给引用 j

解决这个问题也很简单,就是在对参数加上const:对左值引用加上const后,其也可以引用右值

加上const后,在编译器内有如下过程:

const int& x = 10;
//在编译器内实际进行如下过程
//编译器会用所给右值创建一个临时变量,将其赋值给左值
int temp = 10;
const int& x = temp;

则重载运算符也同理,只需对参数加上const便能完成多个对象相加

Student operator+(const Student& j,const Student& t)
{
	Student x;
	x.id = j.id + t.id;
	return x;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值