我有一个类fraction
定义为:
class Fraction
{
int d_numerator;
int d_denominator;
Fraction(numerator, denominator)
:
d_numerator(numerator), d_denominator(denominator)
{}
Fraction(double number)
:
d_numerator(static_cast<int>(number * 100000)), d_denominator(100000)
{}
};
我需要重载运算符+
以允许添加2个分数
对象:
Fraction Fraction::operator+(const Fraction& other)
{
Fraction result = Add(other); //Add() implementation omitted for brevity
return result;
}
我有一个重载的运算符(double)
函数,它允许我将fraction
对象强制转换为double
类型,例如double b=(double)a;
其中a
是fraction
类型。
Fraction::operator(double){//omitted for brevity}
我希望能够向分数
添加一个double
,如下所示:分数c=a+2.6;
问题是这将无法编译,因为有几种方法解释语句fraction c=a+2.6;
的转换
我得到以下编译器错误:
错误C2666:“Fraction::Operator+”:3重载具有类似的转换
我认为这其中的实质是,编译器是否应该:
运算符(double)
重载将分数a
转换为双倍,然后将两个双倍相加分数
,然后添加两个分数
?有没有一种方法可以强制编译器使用另一条路由中的一条,或者让编译器选择任何一条。 只要结果如所料,我不介意。
谢谢
其中一个问题是在将adding运算符声明为成员函数时缺少常量
。
如果方法不是常量
,那么当使用运算符+
时,大多数编译器都会抱怨。
class Fraction
{
public:
Fraction(int numerator, int denominator);
Fraction(int value); // needed to prevent unplanned use of Fraction(double number);
Fraction(double number);
// rule of zero!
Fraction added(const Fraction& b) const; // this returns result of adding current object with argument
void add(const Fraction& b); // NO const! this adds value to current object
private:
int d_numerator;
int d_denominator;
};
Fraction operator+(const Fraction& a, const Fraction& b)
{
return a.added(b);
}
godbolt或cppinsights
我制作了一个工作示例,用于在代码中添加两个带有注释的分数
。 用其他操作符扩展它是一个练习。
我还使用了C++17函数std::gcd
,因为在使用这些函数时,数字越小越好。
#include <iostream>
#include <numeric> // std::gcd
class Fraction {
public:
Fraction(int numerator, int denominator) :
d_numerator(numerator), d_denominator(denominator)
{
inorm();
}
// a converting constructor
explicit Fraction(double number) :
d_numerator(static_cast<int>(number * 1000000)), d_denominator(1000000)
{
norm();
}
// add a Fraction to *this
Fraction& operator+=(const Fraction& o) {
d_numerator = d_numerator* o.d_denominator + o.d_numerator * d_denominator;
d_denominator *= o.d_denominator;
norm();
return *this;
}
// implicit conversion to double
operator double () const {
return static_cast<double>(d_numerator) / d_denominator;
}
// for printing a Fraction
friend std::ostream& operator<<(std::ostream&, const Fraction&);
private:
int d_numerator;
int d_denominator;
void norm() {
// find the greatest common divisor and apply it
const auto gcd = std::gcd(d_numerator, d_denominator);
d_numerator /= gcd;
d_denominator /= gcd;
}
void inorm() {
if(d_numerator == 0) d_denominator = 1;
else if(d_denominator == 0) throw std::runtime_error("denominator==0");
norm();
}
};
std::ostream& operator<<(std::ostream& os, const Fraction& f) {
return os << '(' << f.d_numerator << '/' << f.d_denominator << ')';
}
// A free function to add two Fractions - take the left hand side by value
// and you can return the same object (after having added the right hand side to it).
Fraction operator+(Fraction a, const Fraction& b) {
// use the member operator+=
return a += b;
}
int main() {
Fraction a(1, 2);
Fraction b(0.748624); // use the converting constructor
auto c = a + b; // use the free function
std::cout << c << '\n'; // (78039/62500)
double d = c; // use implicit conversion to double
std::cout << d; // 1.24862
}