重载运算符或数字转换的麻烦

时间:2013-03-29 22:14:30

标签: c++ operator-overloading type-conversion

我正在学习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 个答案:

答案 0 :(得分:3)

问题是您的班级Fraction有一个构造函数,声明为explicit,并且可以接受一个int类型的参数。因此,编译器可以选择此构造函数,以便每次需要Fraction时实现隐式的用户定义转换序列,但提供int

此外,您的类型Fraction还有一个转化运算符float,这使得每次Fraction时隐式转换floatfloat成为可能是必需的,但提供了Fraction

因此,以下说明含糊不清:

CFraction result1 = fraction1*2;

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

在C ++ 11中,您可以决定制作转换运算符fraction1,这样可以避免歧义:您将无法再将2转换为{{1}所以编译器只能选择将2转换为Fraction并调用operator *的重载。

在这种情况下,如果您要执行从Fractionfloat的转换,您必须明确地编写转换:

float f = static_cast<float>(result1);

另一种方法是创建构造函数explicit而不是转换运算符,这样当提供可转换为整数的单个值时,编译器将无法静默实例化Fraction

这将解决上述乘法本身的模糊性,因为它使编译器只能通过转换运算符将fraction1转换为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);

答案 1 :(得分:0)

    CFraction result2 = fraction1 * 2;

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

   fraction1 * 2

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

答案 2 :(得分:0)

因为您在CFraction类中提供了float的转换,所以编译器可以选择转换

CFraction result1 = fraction1*2;

使用自己的运算符*和CFractions,或标准运算符*使用float和int。

如果您可以使用C ++ 11,则可以使用explicit标记浮点转换。否则,将其重命名为&#34; as_float&#34;。隐式转换通常是有问题的,最好避免。

答案 3 :(得分:0)

尝试使用模板并将转换保留给编译器。