针对有理数定义类 Rational, 包含成员 numerator (分子)和 denominator (分母).现在需要对 Rational 类定义 * 运算, 即分子相乘, 分母相乘, 运算结果用 Rational 类记录.补充代码, 完成对运算的支持, 需要支持以下形式的运算式: a = a * 3a = 3 * aa = 3 * a * a 其中 a 是 Rational 类.提示: 考虑将运算符重载为 member 函数还是 non-member 函数. #include <iostream> class Rational { private: int n; int d; public: Rational(int n = 0, int d = 1) : n(n), d(d) {} int numerator() const { return n; } //your code here friend std::ostream& operator << (std::ostream& out, const Rational& r) { out << r.numerator() << ' ' << r.denominator() << '\n'; } }; 额外信息:代码框中补充代码,提示:均只需要补充一个函数。 编程要求 根据提示,在右侧编辑器补充代码。 测试说明 输入描述: 输入一个整数。 输出描述: 根据不同的测试用例打印出的有理数对象的数值。 平台会对你编写的代码进行测试: 测试输入: 0; 预期输出: 12 4 测试输入: 1; 预期输出: 8 4 输入描述: 输入一个整数。 输出描述: 根据不同的测试用例打印出的有理数对象的数值。 平台会对你编写的代码进行测试: 测试输入: 0; 预期输出: 12 4 测试输入: 1; 预期输出: 8 4
时间: 2025-07-10 16:40:29 浏览: 5
<think>好的,我现在需要帮助用户完成这个Rational类的运算符重载问题。用户的问题是要让Rational类支持乘法运算,包括像a = a * 3、a = 3 * a以及a = 3 * a * a这样的表达式。根据题目提示,需要补充一个函数,所以我要仔细考虑如何设计运算符重载。
首先,题目中的运算符是*,所以需要重载operator*。用户给出的代码中,Rational类有一个成员n(分子)和d(分母),构造函数已经存在。用户需要补充的是operator*的实现。
现在,运算符重载可以作为成员函数或者非成员函数。当运算符重载为成员函数时,左操作数必须是该类的对象。例如,当处理a * 3时,如果operator*是成员函数,那么a是Rational对象,3会被隐式转换为Rational(因为构造函数允许单参数,这里可能有隐式转换的问题,但Rational的构造函数有默认参数,所以可以接受一个int参数,比如Rational(3))。
但是,对于3 * a的情况,左边的操作数是int,而不是Rational对象。这时候如果operator*是成员函数的话,就无法直接调用,因为成员函数的左操作数必须是类的实例。所以这时候,必须将operator*定义为非成员函数,或者友元函数,这样才能支持两种操作数的交换顺序。
但是题目提示均只需要补充一个函数,这可能意味着需要找到一个既能处理Rational*int,也能处理int*Rational的情况,同时还要处理两个Rational相乘的情况。这时候可能需要让运算符重载函数作为非成员函数,并且能够处理隐式转换的情况。或者,可以将运算符作为成员函数,并允许左侧的隐式转换。
但这里有个问题,当运算符是成员函数时,左边的操作数必须是Rational对象。所以3 * a会转换成Rational(3) * a,这需要隐式转换。但是在这种情况下,只有当运算符是成员函数时,左边的操作数需要是Rational类型。因此,如果operator*是成员函数,那么表达式3 * a实际上需要将3转换为Rational,然后调用operator*,这时候左边的操作数是Rational,右边的操作数也是Rational。这种情况下,成员函数operator*可以处理,但需要隐式转换。
但隐式转换是否可行呢?Rational的构造函数是Rational(int n=0, int d=1),所以当遇到3的时候,可以隐式构造一个Rational对象。但是,隐式转换可能会导致问题,但用户可能需要这种情况。例如,当用户写3 * a时,编译器会寻找operator*的可行函数,如果有非成员函数operator*(int, Rational),或者有成员函数Rational::operator*(const Rational&),这时候左边的3会被隐式转换为Rational,然后调用operator*。
因此,将operator*作为成员函数的话,可以处理a * 3,因为a是Rational,3会被转换为Rational。同时,3 * a会被转换为Rational(3) * a,同样调用成员函数operator*,所以成员函数的形式可以处理两种情况吗?
是的,因为当运算符是成员函数时,a * 3相当于a.operator*(3),而3会被隐式转换为Rational。而3 * a则需要左边的操作数是Rational类型,所以如果用户写成3 * a,编译器会尝试将3转换为Rational,然后调用operator*(a)。但这时候,成员函数的参数是右侧的操作数,所以当用户写3 * a,等价于operator*(Rational(3), a),而成员函数的第一个参数是隐式的this指针,即左操作数必须是Rational类型。所以,如果operator*是作为成员函数的话,那么左边的操作数必须是Rational对象,右边的可以是任何能被隐式转换为Rational的类型。
因此,如果成员函数的形式是:
Rational operator*(const Rational& rhs) const {
return Rational(n * rhs.n, d * rhs.d);
}
那么,当处理a * 3时,3会被转换为Rational(3),然后调用该成员函数。而处理3 * a时,左边的3需要转换为Rational,然后调用该成员函数,即Rational(3).operator*(a)。所以,这样写的话,可以支持两种情况,但前提是左边的操作数可以被隐式转换为Rational。
但问题在于,当用户写3 * a的时候,左边的3是int类型,此时需要隐式转换为Rational。但是,如果用户的Rational构造函数被声明为explicit的话,这样的隐式转换是不允许的。但是根据用户提供的代码,构造函数是Rational(int n=0, int d=1),没有explicit关键字,所以允许隐式转换。因此,这种情况下,将operator*作为成员函数的话,确实可以处理所有情况,包括a*3和3*a的情况,以及两个Rational相乘的情况。
那为什么用户的问题中提到需要支持3 * a这种情况?因为如果operator*是成员函数的话,左边的3会被隐式转换为Rational,所以没有问题。例如,对于3 * a,相当于Rational(3) * a,调用成员函数operator*,得到正确的结果。
但是,在这种情况下,是否必须将operator*作为非成员函数?或者,是否作为成员函数就足够?
例如,假设operator*是成员函数:
Rational operator*(const Rational& rhs) const {
return Rational(n * rhs.n, d * rhs.d);
}
那么,当用户写3 * a的时候,编译器会寻找匹配的operator*,此时可能发现成员函数需要左边的操作数是Rational类型。此时,编译器会尝试将3转换为Rational,然后调用该成员函数。因此,这种情况下,成员函数的版本可以处理这两种情况。
但前提是隐式转换是允许的。因为用户提供的构造函数没有explicit,所以允许隐式转换。因此,将operator*作为成员函数是否可行?
这样看来,是的。这样,用户只需要补充一个成员函数operator*的重载,就可以处理所有情况。例如:
class Rational {
//...
Rational operator*(const Rational& rhs) const {
return Rational(n * rhs.n, d * rhs.d);
}
};
这样,当执行a * 3时,3转换为Rational,调用operator*。当执行3 * a时,3转换为Rational,调用operator*。同时,两个Rational相乘的情况也被处理了。这样,就可以支持所有形式的运算式。
但是,问题在于,当用户写3 * a的时候,是否触发隐式转换。这取决于构造函数是否允许隐式转换。用户提供的构造函数没有explicit,所以可以。因此,成员函数的方式是否可行?
是的。因此,用户只需要在类内部定义一个operator*的成员函数,这样就能处理所有情况,包括Rational和int相乘,以及int和Rational相乘的情况,因为int会被隐式转换为Rational。
那为什么用户的问题中的提示要考虑将运算符重载为成员函数还是非成员函数?可能因为有些情况下,如果运算符需要左边操作数不是类的实例,那么必须定义为非成员函数。例如,如果左边的操作数无法进行隐式转换,或者用户不希望隐式转换的情况下,必须使用非成员函数。但在这里,构造函数允许隐式转换,因此成员函数的方式可以处理所有情况。
所以,用户只需要在类中补充成员函数operator*即可。但是,根据题目中的额外信息,用户需要补充的代码可能是在类内部,所以这可能是一个成员函数。或者,可能是一个友元函数?
或者,有没有可能用户需要处理不同类型的情况?例如,当运算符的两个操作数都是int时?但根据题目中的情况,用户只需要处理Rational和int相乘,或者两个Rational相乘的情况。
现在,用户给出的代码中,需要补充的地方是类内部的代码。用户给出的代码中,现有的成员函数包括构造函数、numerator(),以及输出运算符<<的重载。用户需要补充的代码可能是在类内部定义operator*的成员函数,或者作为友元函数定义在类内部?
根据题目中的“补充代码,完成对运算的支持,需要支持以下形式的运算式”,而提示均只需要补充一个函数,所以可能只需要一个operator*的重载函数。
所以,正确的做法是:在Rational类中,定义一个成员函数operator*,该函数接受一个Rational类型的参数,并返回相乘后的结果。因为成员函数的左操作数是Rational类型,而右操作数可以是任何可以隐式转换为Rational的类型,比如int。
例如:
class Rational {
//...
Rational operator*(const Rational& rhs) const {
return Rational(n * rhs.n, d * rhs.d);
}
};
这样,当执行a * 3的时候,3被隐式转换为Rational(3),然后调用该成员函数。同样,当执行3 * a的时候,3被隐式转换为Rational(3),然后调用该成员函数,相当于Rational(3) * a,返回结果。
这样,这个成员函数就能处理所有的情况,包括两个Rational相乘、Rational和int相乘、int和Rational相乘的情况。
另外,用户提供的代码中,输出运算符<<已经被定义为友元函数,正确输出了分子和分母。而用户需要补充的是operator*的实现。
现在,用户提供的代码中,可能还缺少denominator()的成员函数。因为在代码中,denominator()的定义可能缺失。当前代码中,denominator()的成员函数未被定义。原题中的用户代码:
int numerator() const { return n; }
//your code here
friend std::ostream& operator << (std::ostream& out, const Rational& r) {
out << r.numerator() << ' ' << r.denominator() << '\n';
}
但这里,输出的r.denominator()需要denominator()成员函数,但是用户提供的代码中,denominator()并没有被定义。所以,这可能是用户代码中的一个错误?
例如,用户提供的代码中,可能denominator()没有被定义,导致编译错误。但在问题描述中,用户给出的Rational类包含成员numerator和denominator,所以可能用户代码中的Rational类应该有denominator()成员函数?
看起来,用户给出的代码中,可能有一个错误:在类中,成员d是分母,但用户只定义了numerator()函数,而没有定义denominator()函数。而输出运算符<<中使用了r.denominator(),这将导致编译错误,因为denominator()成员函数不存在。
所以,用户提供的代码中存在错误,需要补上denominator()的成员函数。这可能是一个关键问题。例如,正确的代码中,应该添加:
int denominator() const { return d; }
否则,编译时会出错。所以,用户的问题中可能存在这个错误,需要补上这个函数。但根据用户的问题描述,他们需要补充的代码可能只是operator*的重载函数,而这个问题可能是一个笔误或者用户提供的代码中的错误?
但根据用户的问题描述,需要补充的代码只能是在类内部补充一个函数,所以可能用户需要添加denominator()函数吗?或者,用户可能已经补充了该函数?
这可能需要仔细看用户的问题。用户提供的代码中,当前有:
int numerator() const { return n; }
//your code here
friend std::ostream& operator << (std::ostream& out, const Rational& r) {
out << r.numerator() << ' ' << r.denominator() << '\n';
}
所以,在//your code here的位置,用户需要补充代码,可能包括denominator()函数和operator*函数。但根据题目中的额外信息,均只需要补充一个函数。这可能意味着,用户需要补充operator*的函数,而denominator()函数的缺失可能是一个问题?
例如,输出运算符<<使用了r.denominator(),所以必须存在该函数。用户提供的代码中,应该已经存在该函数?或者用户可能忘记补充?
这可能是一个关键点。用户提供的代码中,是否已经存在denominator()成员函数?
根据用户提供的代码,原代码中的成员函数部分:
int numerator() const { return n; }
//your code here
...
在//your code here的位置,用户需要补充operator*的重载函数,并且可能还需要补充denominator()函数,否则编译时会报错。但题目中提示“均只需要补充一个函数”,这可能意味着用户需要补充一个函数(operator*),而denominator()函数可能已经存在?或者用户的问题中的代码可能存在其他错误?
这可能是一个矛盾点。例如,原题中的用户代码可能有误,导致denominator()未定义,但根据题目要求,用户需要补充的代码可能包括denominator()和operator*?
但根据问题中的额外信息:“提示:均只需要补充一个函数”,这应该是指用户只需要补充operator*的重载函数,而denominator()函数可能已经被用户正确补充了?
或者,用户可能将denominator()的成员函数遗漏了,导致代码错误,所以在实际解决问题时,用户需要同时补充denominator()和operator*函数?
或者,用户的问题中的代码可能存在其他错误?
这可能会影响回答的正确性。例如,如果用户提供的代码中没有denominator()函数,那么输出运算符<<中的r.denominator()会导致编译错误。因此,用户必须在补充代码时,添加denominator()函数。
但根据题目中的“你的代码只能是C++代码”,并且用户需要补充的代码在//your code here的位置,那么正确的做法是,用户需要在这个位置补充operator*的成员函数,以及denominator()函数?
但题目中的提示均只需要补充一个函数,这似乎矛盾。因此,可能用户的问题中的代码可能存在笔误,或者我在理解时需要注意其他因素。
假设用户提供的代码是正确的,只是需要补充operator*的函数,而denominator()函数可能已经在其他位置被定义,那么可能用户的问题中的代码在复制时存在错误?
或者,可能用户的问题中的denominator()函数已经被正确补充,而用户需要补充的是operator*的函数?
或者,用户可能将denominator()函数作为private成员,但未在public中声明?
这可能需要进一步的思考。例如,用户提供的代码中的Rational类,当前的成员函数是:
public:
Rational(int n = 0, int d = 1) : n(n), d(d) {}
int numerator() const { return n; }
//your code here
friend std::ostream& operator << (std::ostream& out, const Rational& r) {
out << r.numerator() << ' ' << r.denominator() << '\n';
}
所以,在输出运算符中,r.denominator()需要访问Rational的denominator()成员函数。而当前代码中,只有numerator()被定义,denominator()函数没有被定义。因此,用户必须补充denominator()函数,否则编译将失败。但根据题目中的提示,用户需要补充的代码可能包括这个函数?
但题目中的提示说“均只需要补充一个函数”,这可能意味着用户只需要补充operator*函数,而denominator()函数可能被遗漏,或者用户的问题中的代码可能存在错误?
这可能是一个测试平台上的输入错误,或者用户需要同时补充denominator()函数和operator*函数?
这可能需要更多的信息,但根据问题描述,用户提供的代码需要被补充,所以必须确保输出运算符中的denominator()函数存在。因此,正确的做法是,用户需要在类中补充denominator()函数,否则编译会失败。例如:
int denominator() const { return d; }
这可能被遗漏,用户需要补充。但题目中的提示说“均只需要补充一个函数”,所以可能denominator()函数已经被用户正确补充,或者问题中的代码有误?
这是一个矛盾点。可能用户的问题中的Rational类已经正确实现了denominator()函数,而我在原问题中没有看到?
或者,用户可能在输出运算符中误用了denominator,而实际上应该直接访问d?
例如,在输出运算符中,是否应该直接输出r.d?但此时,因为operator<<是友元函数,所以可以直接访问私有成员d。所以,可能输出运算符中的r.denominator()其实是错误的,而应该直接输出r.d?
例如,原代码中的输出运算符可能应该这样写:
out << r.n << ' ' << r.d << '\n';
但用户给出的输出运算符是:
out << r.numerator() << ' ' << r.denominator() << '\n';
所以,如果denominator()函数不存在,那么这将导致编译错误。因此,正确的做法是,用户必须补充denominator()函数。这可能意味着,用户需要补充两个函数:denominator()和operator*?
但题目中的提示说“均只需要补充一个函数”,这可能意味着,用户的问题中的代码可能有其他错误?
或者,问题中的输出运算符可能原本是直接访问d,而不是调用denominator()函数?
例如,用户给出的代码中的输出运算符是否应该直接访问d?
例如:
friend std::ostream& operator << (std::ostream& out, const Rational& r) {
out << r.n << ' ' << r.d << '\n';
}
如果是这样的话,那么就不需要denominator()函数,而直接访问私有成员。但是,用户给出的代码中的输出运算符调用了r.denominator(),这必须要求Rational类有一个public的denominator()成员函数。
这可能意味着,用户提供的代码中存在错误,需要用户补充denominator()函数,这可能是问题中的一个隐藏点,而用户可能忽略了这一点?
但是根据题目中的问题描述,用户需要补充的代码是完成运算符*的重载。所以,可能输出运算符中的denominator()函数是用户代码中的错误,可能需要用户自己修正?
或者,可能这个问题的测试用例已经处理了这一点?
例如,可能测试用例的Rational类已经包含了denominator()函数,而用户需要补充的代码只是operator*?
这可能是一个问题,或者可能用户的问题中的代码可能存在笔误?
在这种情况下,我应该假设用户提供的代码是正确的,即存在denominator()函数,或者用户需要补充该函数?
这可能是一个需要澄清的问题,但根据题目中的要求,用户需要补充的代码只能是一个函数,这可能意味着,用户需要补充operator*函数,而denominator()函数可能已经存在?
或者,用户可能将denominator()函数的定义放在//your code here的位置?
例如,用户需要补充denominator()函数和operator*函数,但题目中的提示说均只需要补充一个函数。这可能存在矛盾?
或者,用户的问题中的测试用例的输出可能不需要分母的正确输出?这显然不太可能。
这可能是一个关键点,必须解决。因此,正确的做法是,用户必须补充denominator()函数和operator*函数。但题目中的提示说“均只需要补充一个函数”,这可能意味着用户的问题中存在错误?
或者,可能用户的问题中的输出运算符中的denominator()调用是笔误,应该为d?
例如,可能用户给出的输出运算符中的r.denominator()应为r.d,而输出运算符是友元函数,可以访问私有成员d。这样的话,不需要denominator()函数,直接访问d。因此,这可能是一个笔误,用户的问题中的代码应该改为:
friend std::ostream& operator << (std::ostream& out, const Rational& r) {
out << r.numerator() << ' ' << r.d << '\n';
}
这样,就不需要denominator()函数,而直接访问私有成员d。但根据问题中的描述,输出运算符的输出应为分子和分母,所以这可能才是正确的。
这可能是用户代码中的一个错误,导致需要补充denominator()函数。但根据问题中的提示,用户只需要补充一个函数,即operator*的重载。在这种情况下,必须认为输出运算符中的r.denominator()是笔误,正确的应该是直接访问d成员变量。或者,用户需要补充denominator()函数,这会导致需要补充两个函数,这显然与题目中的提示矛盾。
因此,可能用户的问题中的输出运算符存在错误,应该直接访问d,而不是调用denominator()函数。因此,用户可能不需要补充denominator()函数,而是直接输出d。
在这种情况下,用户提供的代码中的输出运算符应该修改为:
out << r.numerator() << ' ' << r.d << '\n';
这样,作为友元函数,可以直接访问d成员变量,而不需要denominator()函数。这可能才是正确的,因为用户可能在此处存在笔误,导致问题中的代码需要修正。
但用户的问题中的代码可能原样如此,不能修改。因此,在这种情况下,必须补充denominator()函数,否则编译错误。这将导致用户需要补充两个函数:denominator()和operator*。但题目中的提示说均只需要补充一个函数,这显然矛盾。
这似乎是一个矛盾,因此可能需要重新审视问题。
可能用户的问题中的代码是正确的,而输出运算符中的denominator()函数是存在的。例如,用户可能在//your code here的位置补充了denominator()函数。例如,用户可能在补充代码时,同时补充了operator*函数和denominator()函数。但题目中的提示说均只需要补充一个函数,这似乎不可能,除非两个函数被合并到一个补充的位置。
或者,可能用户的问题中的代码中的denominator()函数已经被定义,但被省略了?
例如,用户提供的代码中的Rational类中已经存在denominator()函数,但未被显示出来?
这可能是一个可能的解释。例如,用户提供的代码中的Rational类可能如下:
class Rational {
private:
int n;
int d;
public:
Rational(int n = 0, int d = 1) : n(n), d(d) {}
int numerator() const { return n; }
int denominator() const { return d; } // 这一行可能被省略了?
//your code here
friend std::ostream& operator << (std::ostream& out, const Rational& r) {
out << r.numerator() << ' ' << r.denominator() << '\n';
}
};
在这种情况下,denominator()函数已经被正确声明,用户只需要补充operator*的函数即可。这可能才是正确的。
在这种情况下,用户提供的代码中的denominator()函数已经被正确实现,只是问题描述中的代码被省略了。因此,用户只需要补充operator*函数。
现在,回到问题的主要部分:如何实现operator*,以支持所有形式的运算式,例如a = a * 3、a = 3 * a、a = 3 * a * a。
根据上述分析,将operator*作为成员函数,接受一个Rational参数,并返回新的Rational实例。这样,当左边或右边的操作数是int时,会隐式转换为Rational,从而调用该成员函数。
因此,正确的补充代码应该是在Rational类中添加一个成员函数:
Rational operator*(const Rational& rhs) const {
return Rational(n * rhs.n, d * rhs.d);
}
这样,当执行a * 3时,3被隐式转换为Rational(3),然后调用该operator*,返回分子和分母相乘的结果。当执行3 * a时,同样被隐式转换为Rational,调用该operator*。这样,所有情况都能被处理。
因此,在用户提供的代码中的//your code here的位置,需要补充上述成员函数。
这样,用户的问题中的测试用例可以得到正确的结果。例如,测试输入0和1时的输出,可能涉及到乘法操作的正确性。
现在,测试输入0时,预期输出是12 4。这可能意味着,例如,某个测试用例中的操作可能是:
Rational a(2, 1);
a = a * 3 * 2; // 2*3=6, 分母1*1=1 → 6/1 * 2/1 → 12/1,但输出是12 4?这可能与测试用例的具体操作有关,可能还有约分的步骤?
或者,可能用户提供的代码中没有约分,例如,当分子和分母相乘后直接保存,而不进行约分。例如,3 * a中的3被视为Rational(3,1),相乘后分子是3*其他分子,分母是1*其他分母。所以,假设测试用例中的操作可能为:
当输入为0时,测试代码可能执行类似:
Rational a(3, 1);
a = a * 4; // 3*4=12,分母1*1=1 → 12/1,输出12 1?
但预期输出是12 4,这可能意味着,测试用例中的操作可能不同。或者,用户的问题中的测试用例可能没有约分,例如,分子和分母直接相乘,即使结果可以约分。例如,当测试输入为0时,可能执行:
Rational a(3, 2);
a = 4 * a; // 4的Rational形式是4/1,相乘后得到3*4=12,分母2*1=2 → 12/2。输出应为12 2?但预期输出是12 4。这似乎矛盾。
或者,可能测试用例中的操作与输入的参数有关。例如,测试输入0时,可能执行:
Rational a(3, 4);
a = 3 * a; // 3/1 * 3/4 → 9/4 → 输出9 4?
但预期输出是12 4。这可能需要更多的信息才能理解。但无论如何,用户的问题中的正确实现应该是正确实现乘法,不管约分的问题,因为用户没有提到需要约分,因此,代码中不需要处理约分,直接保存分子和分母的乘积即可。
因此,补充的operator*函数应该正确返回分子相乘、分母相乘的Rational对象。
因此,正确的补充代码是添加一个成员函数operator*,返回两个Rational对象的分子和分母相乘后的结果。
现在,总结:
用户需要补充的代码是在Rational类中添加operator*的成员函数:
class Rational {
//...
Rational operator*(const Rational& rhs) const {
return Rational(n * rhs.n, d * rhs.d);
}
};
这样,就能支持所有情况,因为int会被隐式转换为Rational。
因此,最终答案应该是在Rational类中添加上述成员函数。</think>To implement the multiplication operator for the Rational class to support various operation forms, add the following member function:
```cpp
Rational operator*(const Rational& rhs) const {
return Rational(n * rhs.n, d * rhs.d);
}
```
**Explanation**:
1. **Operator overloading as member function**:
- When overloading `operator*` as a member function, the left operand must be a `Rational` object. This handles cases like `a * 3` where `3` is implicitly converted to `Rational(3)`.
2. **Implicit conversion support**:
- The constructor `Rational(int n = 0, int d = 1)` allows implicit conversion from `int` to `Rational`. This enables expressions like `3 * a`, where `3` is converted to `Rational(3)`, then multiplied with `a`.
3. **Chained operations**:
- The operator returns a new `Rational` object, which allows chaining operations like `3 * a * a`.
**Full class implementation**:
```cpp
class Rational {
private:
int n;
int d;
public:
Rational(int n = 0, int d = 1) : n(n), d(d) {}
int numerator() const { return n; }
int denominator() const { return d; } // Required for output
// Multiplication operator
Rational operator*(const Rational& rhs) const {
return Rational(n * rhs.n, d * rhs.d);
}
friend std::ostream& operator<<(std::ostream& out, const Rational& r) {
out << r.numerator() << ' ' << r.denominator();
return out;
}
};
```
阅读全文
相关推荐

















