I'm learning about overloaded operators in C++, and i've got a problem.
I wrote a (primitive) class to represent a fraction in c++, and a function to multiply two of them.
If I want to multiply fraction by integer using function, everything works very well (thanks to conversion constructor :P). But now i want to multiply fractions by overloaded *, just like two numbers. Multiply first_fraction * second_fraction
works good, but compilator don't want to convert numbers to fraction in fraction * 2
. (It gaves this error: error C2666: 'operator *' : 2 overloads have similar conversions)
If I convert it manually, using fraction*static_cast<CFraction>(2)
it works again.
Can anyone explain me what am I doing bad? Here's the full code:
#include <iostream>
using namespace std;
class CFraction
{
private:
int m_numerator;
int m_denominator;
public:
// Normal constructor, default constructor and conversion constructor
CFraction(int numerator=0,int denominator = 1) : m_numerator(numerator), m_denominator(denominator)
{
}
int numerator() const { return m_numerator; }
void numerator(int numerator) { m_numerator = numerator; }
int denominator() const { return m_denominator; }
void denominator(int denominator) { m_denominator = denominator; }
// Conversion to decimal form
operator float()
{
return m_numerator / static_cast<float>(m_denominator);
}
};
// Function to multiply 2 fractions
CFraction multiplication(const CFraction& f1,const CFraction& f2)
{
return CFraction(f1.numerator()*f2.numerator(),f1.denominator()*f2.denominator());
}
// Overloaded opearator to multiply 2 fractions
CFraction operator *(const CFraction& f1,const CFraction& f2)
{
return CFraction(f1.numerator()*f2.numerator(),f1.denominator()*f2.denominator());
}
int main()
{
CFraction fraction1(3,4);
cout << "Fraction: "<< fraction1.numerator() << "/" << fraction1.denominator() << endl;
cout << "Decimal: " << static_cast<float>(fraction1) << endl;
// Multiplication by function works very well
CFraction result = multiplication(fraction1,2);
// (ERROR) Compiller won't convert 2 to CFraction class
CFraction result1 = fraction1*2;
// Using manually covnerted integer - works again
CFraction result2 = fraction1*static_cast<CFraction>(2);
cout << "Multiplied by 2: " << static_cast<float>(result);
getchar();
return 0;
}
PS. I'm using MS Visual C+++ 2010 if it's matter
The problem is that your class Fraction
has a constructor which is not declared as explicit
and can accept one argument of type int
. Therefore, this constructor can be picked by the compiler to realize implicit user-defined conversion sequences every time a Fraction
is needed, but an int
is provided.
Moreover, your type Fraction
also has a conversion operator to float
, which makes it possible to implicitly convert Fraction
to float
every time a float
is required, but a Fraction
is provided.
Therefore, the following instruction is ambiguous:
CFraction result1 = fraction1*2;
The compiler doesn't know whether to pick your overload of operator *
for objects of type Fraction
and convert the second argument ( 2
) to a Fraction
by using the constructor of Fraction
an passing 2
as an input, or rather convert the first argument to a float
through the conversion operator and then use the built-in operator *
to perform the multiplication between a float
and an int
.
In C++11, you could decide to make the conversion operator explicit
, and this would prevent the ambiguity: you won't be able anymore to silently get fraction1
converted to 2
, so the compiler will have only the option to convert 2
into a Fraction
and invoke your overload of operator *
.
In this case, if you want to perform the conversion from Fraction
to float
, you have to write the cast explicitly:
float f = static_cast<float>(result1);
The other alternative is to make your constructor explicit
rather than the conversion operator, so that the compiler won't be able to silently instantiate a Fraction
when a single value convertible to an integer is provided.
This will solve the ambiguity for the above multiplication itself, in that it leaves the compiler with the only choice of converting fraction1
into a float
through your conversion operator. However, two problems will arise.
First, you would not be able anymore to write:
CFraction result = multiplication(fraction1, 2);
Because this attempts to create a Fraction
out of the second argument 2
( multiplication()
expects two Fractions
as its arguments). Instead, you would have to construct the object explicitly:
CFraction result = multiplication(fraction1, CFraction(2));
Second, even though your original multiplication above would work, the final copy-initialization of result1
would not, because (once again) that would require an implicit conversion.
Therefore, you would have to rewrite your copy-initialization as:
CFraction result1 = CFraction(fraction1*2);
Or as a direct initialization:
CFraction result1(fraction1*2);
CFraction result2 = fraction1 * 2;
How you use a result has no effect on how it's computed, so this is just:
fraction1 * 2
This is ambiguous. You could convert fraction1
to a float and multiply that by 2. You could convert 2
to a Fraction
and then use operator*
. The compiler has no idea which you want.
Because you supply a conversion to float in your CFraction class, the compiler has a choice of converting
CFraction result1 = fraction1*2;
to use either your own operator * with CFractions, or the standard operator * with a float and an int.
If you can use C++11, you could mark your float conversion with explicit. Otherwise, rename it to something like "as_float". Implicit conversions are often problematic and are best avoided.
尝试使用模板并将转换留给编译器。
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.