重载 * 运算符时不使用 const 的影响

Affect of not using const while overloading * operator

本文关键字:const 影响 运算符 重载      更新时间:2023-10-16

我只是尝试一些代码来理解运算符<<重载,大多数解释都是可以理解的,但我在使用 const 关键字时遇到了一些问题。 下面的代码给了我一个编译错误,说操作数分数不匹配,分数)

#include<iostream>
using namespace std;
class Fraction
{
private:
int m_numerator;
int m_denominator;
public :
Fraction(int val1, int val2):m_numerator(val1),m_denominator(val2){};
void print()
{
cout<<m_numerator<<"/"<<m_denominator<<endl;
}
friend Fraction operator*(Fraction &f1,Fraction &f2);
friend Fraction operator*(Fraction &f1, int value);
friend Fraction operator*(int value,Fraction &f1);
};
Fraction operator*(Fraction &f1,Fraction &f2)
{
return Fraction(f1.m_numerator * f2.m_numerator, f1.m_denominator * f2.m_denominator);
}
Fraction operator*(Fraction &f1, int value)
{
return Fraction(f1.m_numerator * value, f1.m_denominator);
}
Fraction operator*(int value,Fraction &f1)
{
return Fraction(f1.m_numerator * value, f1.m_denominator);
}
int main()
{
Fraction f1(2, 5);
f1.print();
Fraction f2(3, 8);
f2.print();
Fraction f3 = f1 * f2;
f3.print();
Fraction f4 = f1 * 2;
f4.print();
Fraction f5 = 2 * f2;
f5.print();
Fraction f6 = Fraction(1, 2) * Fraction(2, 3) * Fraction(3, 4);
f6.print();
}

上述代码的问题在于,在将其用作函数参数时,Fraction 对象前面没有 const,下面的代码工作正常:

#include<iostream>
using namespace std;
class Fraction
{
private:
int m_numerator;
int m_denominator;
public :
Fraction(int val1, int val2):m_numerator(val1),m_denominator(val2){};
void print()
{
cout<<m_numerator<<"/"<<m_denominator<<endl;
}
friend Fraction operator*(const Fraction &f1,const Fraction &f2);
friend Fraction operator*(const Fraction &f1, int value);
friend Fraction operator*(int value,const Fraction &f1);
};
Fraction operator*(const Fraction &f1,const Fraction &f2)
{
return Fraction(f1.m_numerator * f2.m_numerator, f1.m_denominator * f2.m_denominator);
}
Fraction operator*(const Fraction &f1, int value)
{
return Fraction(f1.m_numerator * value, f1.m_denominator);
}
Fraction operator*(int value,const Fraction &f1)
{
return Fraction(f1.m_numerator * value, f1.m_denominator);
}
int main()
{
Fraction f1(2, 5);
f1.print();
Fraction f2(3, 8);
f2.print();
Fraction f3 = f1 * f2;
f3.print();
Fraction f4 = f1 * 2;
f4.print();
Fraction f5 = 2 * f2;
f5.print();
Fraction f6 = Fraction(1, 2) * Fraction(2, 3) * Fraction(3, 4);
f6.print();
}

为什么 const 在这里扮演如此重要的角色,在某些情况下,我不需要 const 关键字,我将如何处理这些情况。

PS:错误具体在行中: 分数 f6 = 分数(1, 2) * 分数(2, 3) * 分数(3, 4);

任何解释都会有很大帮助。

失败的行是这一行:

Fraction f6 = Fraction(1, 2) * Fraction(2, 3) * Fraction(3, 4);

原因是匿名临时无法修改。 这是一个语言功能,旨在保护您免受自己的侵害,因为通常如果您想修改某些内容,则需要使用结果。 因此,您的非修改运算符需要通过 const-ref 或值获取它们的参数。

你真的需要掌握const正确性。所有函数都告诉编译器它们可以修改传入的参数。

具体而言,这意味着:

Fraction f6 = Fraction(1, 2) * Fraction(2, 3) * Fraction(3, 4);

编译器必须生成如下代码:

Fraction const tmp1 = Fraction(1, 2);
Fraction const tmp2 = Fraction(2, 3);
Fraction const tmp3 = operator*(tmp1, tmp2);
Fraction const tmp4 = Fraction(3, 4);
Fraction f6 = operator*(tmp3, tmp4);

请注意,编译器生成的临时变量实际上并不const,但你不能使用非常量引用绑定到它们(即你应该在函数原型中使用const &而不仅仅是&,或者根本不使用引用),部分原因是如果你编写的代码改变了一个随后消失的临时,这是毫无意义的, 几乎毫无疑问,这不是你想做的。 (历史注释:在至少一个版本的 fortran IV 编译器中 - 所有内容都通过非常量引用传递 - 可以更改数值常数 1 的值,因为该语言没有恒常性或临时变量的概念,导致很多混乱)。

但是您的算术运算符都没有接受const引用(尽管实际上没有更改它们的参数),编译器找不到合适的方法来使用,因此该语句出错。

顺便说一下,您没有运算符<<重载,并且该代码示例中的任何地方都不会实际使用它(如果有的话)。

另请注意,您的print方法不是const,它应该是,否则您将无法在constFraction 对象上使用它。