C++类型转换与隐式构造函数

4
我正在实现一个表示分数的C++类。下面是我的代码。
class Fraction
{
    public:
        Fraction(char i);
        Fraction(int i);
        Fraction(short i);
        Fraction(long int l);
#ifdef __LP64__
        Fraction(long long l);
#endif
        Fraction(float f);
        Fraction(double d);
        Fraction(double x, double y);

        Fraction operator +() const;
        Fraction operator -() const;

        Fraction& operator +=(const Fraction& other);
        Fraction& operator -=(const Fraction& other);
        Fraction& operator *=(const Fraction& other);
        Fraction& operator /=(const Fraction& other);

        bool operator ==(const Fraction& other);
        bool operator !=(const Fraction& other);
        bool operator  >(const Fraction& other);
        bool operator  <(const Fraction& other);
        bool operator >=(const Fraction& other);
        bool operator <=(const Fraction& other);

        operator double();
        operator float();

        static void commonize(Fraction& a, Fraction& b);
        void shorten();

        double getNumerator();
        double getDenominator();

        friend Fraction operator +(Fraction const& a, Fraction const& b);
        friend Fraction operator -(Fraction const& a, Fraction const& b);
        friend Fraction operator *(Fraction const& a, Fraction const& b);
        friend Fraction operator /(Fraction const& a, Fraction const& b);
        friend ostream& operator <<( ostream& o, const Fraction f);

    protected:
        double numerator, denominator;

};

我现在有两个小问题。现在正在尝试呼叫。
Fraction a(1, 2);
cout << (3 + a) << endl;

仅仅导致这个错误:
fractiontest.cpp:26: error: ambiguous overload for ‘operator+’ in ‘3 + a’
fractiontest.cpp:26: note: candidates are: operator+(int, double) <built-in>
fractiontest.cpp:26: note:                 operator+(int, float) <built-in>

我只想要这个:
explicit operator double();
explicit operator float();

但显然,这并不起作用。我希望只有在使用转换符号时才调用这两个转换符号。例如:Fraction f(1, 2); double d = (double)(f);


5
根据梅耶斯在《More Effective C++》中的描述,对于重载转换运算符(和拥有非显式单参数构造函数),你应该三思而后行。 - Oliver Charlesworth
谢谢Oli。我知道存在非显式单参数(也称为转换)构造函数的问题。我想我应该重新考虑一下转换运算符。而且我猜你不能重载int::int(Fraction f),因为int是一个原始类型... - Atmocreations
@Roland:嗯,不错...float没错。其他的并不是非常必要,它们只是为了完整性而存在 ;) 感谢你指出来。 - Atmocreations
所有这些构造函数都是糟糕的设计。只需要一个接受一个或两个 double 的构造函数,如果必要,让调用者进行转换即可。这与完整性无关,因为您未能允许从可以转换为 doublefloat 的 UDT 构造您的类,例如。这很好:它不是您的类的责任将任何类型强制转换为 double,它的责任是像分数一样运作。此外,为什么分数组件要使用浮点数?它们不应该是整数吗?简而言之:选择一种类型(或使您的类成为模板),并放弃其他类型。 - GManNickG
@GMan:嗯,你说得对。不知怎么的,我已经知道会有人提出这个问题:P 我必须承认这是作业,有时候给出的例子毫无意义。无论如何,还是谢谢你 :) - Atmocreations
显示剩余2条评论
2个回答

3
去除转换运算符,3 + a 应该使用你的朋友 operator+ ,并通过隐式构造函数 Fraction(int i);3 隐式转换为 Fraction
编辑:对于显式转换运算符,C++0x 具体允许此操作:

12.3.2 [class.conv.fct] p2 转换函数可以是显式的,在这种情况下,它仅被视为直接初始化的用户定义转换。

C++03 标准没有具体提到此内容。

谢谢您的非常快速的回复。这个方法确实有效,就像我之前使用过的那个一样。但是现在当我想要将它转换为double类型时,唯一的方法是创建一个成员函数来完成,对吗?这意味着它不是自动的... - Atmocreations
1
甚至更好的做法是定义operator+(int, const Fraction&),并消除同样令人不悦的隐式构造函数! - Oliver Charlesworth
@Atmo:是的,要么这样,要么使用手动转换的explicit operator3 + (int)a;。通常更喜欢成员函数,因为隐式转换可能会非常危险。 - Xeo
@Oli:我认为为类拥有隐式构造函数是完全可以的,因为其他方式会导致很多代码重复。 - Xeo
1
@Xeo:我同意关于代码重复的观点(尽管可以通过在例如operator+(const Fraction&, const Fraction&)中定义'operator+(int,const Fraction&)来解决这个问题)。但恰好这种类是隐式构造函数为什么不好的典型示例,因为它们增加了以打字错误为基础的难以发现的bug的方式数量。 - Oliver Charlesworth
显示剩余3条评论

3

按照定义,转换运算符是隐式的。您无法将它们显式化。

通常的解决方案是使用成员函数来进行转换。我认为您还可以创建一个专门的模板方法,它看起来就像一个static_cast,并调用显式类方法。


请查看我的答案评论,关于显式转换运算符的内容,我正在搜索C++0x FDIS。 - Xeo
谢谢,马克。因此,“自动转换”似乎不可能。成员函数可以使用,我知道什么是static_cast,但你能给我一个提示,你所说的static_cast方法是什么吗? - Atmocreations

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接