解决C++运算符重载时=和+(或-、*、/、后置自增自减)无法连用

背景题目:
定义有理数类(分母不为0的分数,分子分母均为整数)Rational,实现相应操作符的重
载。
(1)定义私有数据成员:分子int iUp; 分母 int iDown。
(2)定义私有成员函数:void Reduce() 和 int Gcd(int l, int r),分别用于有理数的
约简和求两个整数的最大公约数。其中,在约简时需要求取分子与分母的最大公约数。
(3)定义构造函数,在构造函数体内可调用Reduce对有理数进行约简。
(4)将负号-和赋值运算符=重载为公有成员函数,分别用于求有理数的负数和赋值。
(5)将前置++、前置–、后置++、后置–重载为公有成员函数,实现有理数自增1或自减
1。
(6)将+、-、*、/重载为友员函数,实现有理数的加减乘除。
(7)将<、<=、>、>=重载为友员函数,实现有理数的大小关系比较。
(8)重载流插入符<<和流提取符>>,分别用于有理数的输出和输入。其中,输出格式为
“分子/分母”,若为整数,则直接输出整数。
为便于说明,此处只给出部分代码:

#include<iostream>

using namespace std;

class Rational
{
private:	
	int iUp;
	int iDown;

	void Reduce()
	{
         ...
	}
	int Gcd(int l, int r)
	{
		...
	}

public:
	Rational(){}
	Rational(int u, int d)
	{
		...
	}

	Rational& operator=(Rational& r)
	{
		iUp=r.iUp;
		iDown = r.iDown;
		Reduce();
		return *this;
	}

	Rational operator-()
	{
		Rational temp;
		temp.iUp = -iUp;
		temp.iDown = iDown;
		return temp;
	}
	Rational& operator++()
	{
		iUp += iDown;
		Reduce();
		return *this;
	}
	Rational operator++(int)
	{
		Rational temp = *this;
		iUp += iDown;
		Reduce();
		return temp;
	}
	Rational& operator--()
	{
		iUp -= iDown;
		Reduce();
		return *this;
	}
	Rational operator--(int)
	{
		Rational temp = *this;
		iUp -= iDown;
		Reduce();
		return temp;
	}

	friend Rational operator+(const Rational& a, const Rational& b);
	friend Rational operator-(const Rational& a, const Rational& b);
	friend Rational operator*(const Rational& a, const Rational& b);
	friend Rational operator/(const Rational& a, const Rational& b);

	friend bool operator<(const Rational& a, const Rational& b);
	friend bool operator<=(const Rational& a, const Rational& b);
	friend bool operator>(const Rational& a, const Rational& b);
	friend bool operator>=(const Rational& a, const Rational& b);

	friend istream& operator>>(istream& in, Rational& r);
	friend ostream& operator<<(ostream& out, const Rational& r);
};

Rational operator+(const Rational& a, const Rational& b)
{
	Rational temp;
	temp.iUp = a.iUp * b.iDown + b.iUp * a.iDown;
	temp.iDown = a.iDown * b.iDown;
	temp.Reduce();
	return temp;
}
Rational operator-(const Rational& a, const Rational& b)
{
	Rational temp;
	temp.iUp = a.iUp * b.iDown - b.iUp * a.iDown;
	temp.iDown = a.iDown * b.iDown;
	temp.Reduce();
	return temp;
}
Rational operator*(const Rational& a, const Rational& b)
{
	Rational temp;
	temp.iUp = a.iUp * b.iUp;
	temp.iDown = a.iDown * b.iDown;
	temp.Reduce();
	return temp;
}
Rational operator/(const Rational& a, const Rational& b)
{
	Rational temp;
	temp.iUp = a.iUp * b.iDown;
	temp.iDown = a.iDown * b.iUp;
	temp.Reduce();
	return temp;
}

bool operator<(const Rational& a, const Rational& b)
{
	...
}
bool operator<=(const Rational& a, const Rational& b)
{
	...
}
bool operator>(const Rational& a, const Rational& b)
{
	...
}
bool operator>=(const Rational& a, const Rational& b)
{
	...
}

istream& operator>>(istream& in, Rational& r)
{
	...
}
ostream& operator<<(ostream& out, const Rational& r)
{
	...
}

int main()
{
	int up, down;
	cin >> up >> down;
	Rational a(up, down);
	cin >> up >> down;
	Rational b(up, down);
	Rational c;

	c = a + b;
	cout << "a+b: " << c;
	c = a - b;
	cout << "a-b: " << c;
	c = a * b;
	cout << "a*b: " << c;
	c = a / b;
	cout << "a/b: " << c;
	c = -a;
	cout << "-a: " << c;
	c = ++a;
	cout << "++a: " << c;
	c = --a;
	cout << "--a: " << c;
	c = a++;
	cout << "a++: " << c;
	c = a--;
	cout << "a--: " << c;
	...
	return 0;
}

欲运行代码,结果报错:
在这里插入图片描述可以看到等号与+、-、*、/、后置自增、后置自减连用的地方,都标红,报错信息为“error C2679: 二进制“=”: 没有找到接受’Rational’类型的右操作数的运算符(或没有可接受的转换)”。
可是赋值运算符已经重载了,为什么这里会没有起作用呢?经过查询,我发现,问题出在重载等号传入的参数和其他运算符的返回值类型上。
源码中重载等号的参数类型是Rational&,是一个可变引用

	Rational& operator=(Rational& r)
	{
		iUp=r.iUp;
		iDown = r.iDown;
		Reduce();
		return *this;
	}

重载+、-、*、/、后置自增、后置自减的返回参数均为Rational,是一个临时局部变量。

Rational operator+(const Rational& a, const Rational& b)
{
	Rational temp;
	temp.iUp = a.iUp * b.iDown + b.iUp * a.iDown;
	temp.iDown = a.iDown * b.iDown;
	temp.Reduce();
	return temp;

在C++里,临时局部变量没有合法内存空间,是不可以转为可变引用的,因为可变引用需要有合法的内存空间。但是常量引用可以接收这一类没有有效内存空间的值,即const Rational&。
于是我将重载等号代码修改,

	Rational& operator=(const Rational& r)
	{
		iUp=r.iUp;
		iDown = r.iDown;
		Reduce();
		return *this;
	}

问题就解决了。
在这里插入图片描述接下来讲一下常量引用的原理,以整型常量引用为例:

int &a=10;//会报错,10没有申请合法内存空间
const int &a=10;//不会报错
                //编译器会自动将代码优化为int temp=10;
                                      //const int &a=temp;

总结:
当不涉及修改数据操作时,传递参数最好用常量引用的形式,即const type&,因为这个方式是适应性最高的,可以接收有合法内存空间的变量或常量,也可以接收没有事先申请合法内存空间的临时(局部)变量或常量,还可以保护数据,防止误操作。

原创文章 34 获赞 87 访问量 2731

猜你喜欢

转载自blog.csdn.net/qq_44643644/article/details/105646203