1

我正在学习 C++ 中的重载运算符,但我遇到了问题。

我写了一个(原始)类来表示 C++ 中的一个分数,以及一个将其中两个相乘的函数。

如果我想使用函数将分数乘以整数,那么一切都很好(感谢转换构造函数:P)。但现在我想用重载的 * 乘以分数,就像两个数字一样。乘法first_fraction * second_fraction效果很好,但编译器不想将数字转换为fraction * 2. (它给出了这个错误:错误 C2666:'operator *':2 个重载有类似的转换)

如果我手动转换它,fraction*static_cast<CFraction>(2)则可以再次使用它。

谁能解释我做错了什么?这是完整的代码:

#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。如果重要的话,我正在使用 MS Visual C++ 2010

4

4 回答 4

3

问题是你的类Fraction有一个构造函数,它没有被声明为explicit并且可以接受一个类型的参数int。因此,每次Fraction需要a,但int提供了an时,编译器都可以选择这个构造函数来实现隐式的用户自定义转换序列。

此外,您的类型Fraction还有一个转换运算符 to float,这使得每次需要 a 时都可以隐式转换Fraction为,但提供了 a 。floatfloatFraction

因此,以下指令是模棱两可的:

CFraction result1 = fraction1*2;

编译器不知道是否选择operator *类型对象的重载并使用传递的构造函数作为输入Fraction将第二个参数 ( 2) 转换为 a ,或者通过转换运算符将第一个参数转换为 a 然后使用内置函数执行 a和 an之间的乘法。FractionFraction2floatoperator *floatint

在 C++11 中,您可以决定制作转换运算符explicit,这样可以防止歧义:您将无法再默默地fraction1转换为2,因此编译器只能选择转换2为 aFraction并调用您的的超载operator *

在这种情况下,如果要执行从Fractionto的转换float,则必须显式编写强制转换:

float f = static_cast<float>(result1);

另一种选择是使您的构造函数而不是转换运算符,以便在提供可转换为整数的单个值时explicit,编译器将无法静默实例化 a 。Fraction

这将解决上述乘法本身的歧义,因为它使编译器只能选择通过转换运算符转换fraction1为 a float。但是,会出现两个问题。

首先,您将无法再编写:

CFraction result = multiplication(fraction1, 2);

因为这试图Fraction从第二个参数中创建一个2multiplication()期望两个Fractions作为它的参数)。相反,您必须明确地构造对象:

CFraction result = multiplication(fraction1, CFraction(2));

其次,即使您上面的原始乘法可以工作,最终的复制初始化result1也不会,因为(再一次)这需要隐式转换。

因此,您必须将复制初始化重写为:

CFraction result1 = CFraction(fraction1*2);

或者作为直接初始化:

CFraction result1(fraction1*2);
于 2013-03-29T22:20:45.223 回答
0
    CFraction result2 = fraction1 * 2;

你如何使用结果对它的计算方式没有影响,所以这只是:

   fraction1 * 2

这是模棱两可的。您可以转换fraction1为浮点数并将其乘以 2。您可以转换2为 aFraction然后使用operator*. 编译器不知道你想要哪个。

于 2013-03-29T22:21:50.143 回答
0

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.

于 2013-03-29T22:33:39.437 回答
0

Try to use templates and left conversions to compiler.

于 2013-03-30T18:37:30.860 回答