【问题标题】:Troubles with overloading operator or numbers conversion重载运算符或数字转换的问题
【发布时间】:2013-03-20 16:27:32
【问题描述】:

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

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

如果我想使用函数将分数乘以整数,一切都很好(感谢转换构造函数:P)。但是现在我想将分数乘以重载的 *,就像两个数字一样。乘以first_fraction * second_fraction 效果很好,但编译器不想将fraction * 2 中的数字转换为分数。 (它给出了这个错误:error 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

【问题讨论】:

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


    【解决方案1】:

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

    此外,您的类型Fraction 还具有到float 的转换运算符,这使得每次需要float 时都可以将Fraction 隐式转换为float,但提供了Fraction .

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

    CFraction result1 = fraction1*2;
    

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

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

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

    float f = static_cast<float>(result1);
    

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

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

    首先,你不能再写了:

    CFraction result = multiplication(fraction1, 2);
    

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

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

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

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

    CFraction result1 = CFraction(fraction1*2);
    

    或者直接初始化:

    CFraction result1(fraction1*2);
    

    【讨论】:

    • 感谢您详尽的回答
    【解决方案2】:
        CFraction result2 = fraction1 * 2;
    

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

       fraction1 * 2
    

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

    【讨论】:

      【解决方案3】:

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

      CFraction result1 = fraction1*2;
      

      将您自己的运算符 * 与 CFractions 一起使用,或者将标准运算符 * 与浮点数和整数一起使用。

      如果你可以使用 C++11,你可以用显式标记你的浮点转换。否则,将其重命名为“as_float”。隐式转换通常有问题,最好避免。

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          猜你喜欢
          • 2011-03-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多