C++ Primer 学习笔记_64_重载操作符与转换 --转换与类类型 (二)

2014-11-24 12:41:39 · 作者: · 浏览: 1
的重载操作符、转换构造函数和转换函数需要多加小心。尤其是,如果类既定义转换操作符又定义了重载操作符,容易产生二义性。下面几条经验规则会有所帮助:

1)不要定义相互转换的类,即如果类Foo具有接受类Bar的对象的构造函数,不要再为类Bar定义到类型Foo的转换操作符

2)避免到内置算术类型的转换。具体而言,如果定义了到算术类型的转换,则

a)不要定义接受算术类型的操作符的重载版本。如果用户需要使用这些操作符,转换操作符将转换你所定义的类型的对象,然后可以使用内置操作符。

b)不要定义转换到一个以上算术类型的转换。让标准转换提供到其他算术类型的转换

最简单的规则是:对于那些“明显正确”的,应避免定义转换函数并限制非显式构造函数

3、转换可能引起内置操作符的二义性

class SmallInt
{
public:
    SmallInt(int = 0);
    operator int() const
    {
        return val;
    }

    friend SmallInt operator+(const SmallInt &,const SmallInt &);
private:
    std::size_t val;
};

int main()
{
    SmallInt s1,s2;

    //使用接受两个 SmallInt 值的 + 的重载版本
    SmallInt s3 = s1 + s2;  //OK

    //以将 0 转换为 SmallInt 并使用 + 的 SmallInt 版本
    //也可以将 s3 转换为 int 值并使用 int 值上的内置加操作符。
    int i = s3 + 0; //Error
}


【小心地雷】

既为算术类型提供转换函数,又为同一类类型提供重载操作符,可能会导致重载操作符和内置操作符之间的二义性。

4、可行的操作符和转换

通过为每个调用列出可行函数,可以理解这两个调用的行为。在第一个调用中,有两个可行的加操作符:

    SmallInt operator+(const SmallInt &,const SmallInt &);
    内置的 operator+(int, int)

第一个加不需要实参转换—— s1和 s2与形参的类型完全匹配。使用内置加操作符对两个实参都需要转换,因此,重载操作符与两个实参匹配得较好,所以将调用它。

对于第二个加运算:

    int i = s3 + 0; // error: ambiguous

两个函数同样可行。在这种情况下,重载的+版本与第一个实参完全匹配,而内置版本与第二个实参完全匹配。第一个可行函数对左操作数而言较好,而第二个可行函数对右操作数而言较好。因为找不到最佳可行函数,所以将该调用标记为有二义性的。

//P466 习题14.46 最后的一条语句会调用哪个operator+
class Complex
{
public:
    Complex(double);
};

class LongDouble
{
    friend LongDouble operator+(LongDouble &,int);  //1

public:
    LongDouble(int);
    operator double ();
    LongDouble operator+(const Complex &);      //2
    //..
};
LongDouble operator+(const LongDouble &,double);    //3

int main()
{
    LongDouble ld(16.08);
    double res = ld + 15.05;    //调用3,为什么呢?
}