12.6.4 自动类型转换的缺陷
因为编译器必须选择如何执行类型转换,所以如果没有正确地设计出转换,编译器会产生麻烦。类X可以用operator Y()将它本身转换到类Y,这是一个简单且明显的情况。如果类Y有一个单个参数为X的构造函数,这也表示同样的类型转换。现在编译器有两个从X到Y的转换方法,所以当发生转换时,编译器会产生一个二义性转换错误:
这个问题的解决方法是不要那样做,而是仅提供单一的从一个类型到另一个类型的自动转换方法。
当提供了转换到不止一种类型的自动转换时,会发生一个更难解决的问题。有时,这个问题被称为扇出(fan-out):
类Apple有向Orange和Pear的自动转换。这样存在一个隐藏的缺陷:使用了创建的两种版本的重载运算符eat()时就出现问题了(只有一个版本时,main()里的代码会正常运行)。
通常,对于自动类型的解决方法是只提供一个从某类型向另一个类型转换的自动转换版本。当然也可以有多个向其他类型的转换,但它们不应该是自动转换,而应该用如makeA()和makeB()这样的名字来创建显式的函数调用。
12.6.4.1 隐藏的行为
自动类型转换会引入比所希望的更多的潜在行为。下面要费点力去理解了,看看CopyingVsInitialization.cpp修改后的例子:
这里没有从Fo对象创建Fee fee的构造函数。然而,Fo有一个到Fee的自动类型转换。这里也没有从Fee对象创建Fee的拷贝构造函数,但这是一种能由编译器帮助我们创建的特殊函数之一(默认的构造函数、拷贝构造函数、operator=和析构函数可自动创建)。对于下面正确的声明:
自动类型转换运算符被调用并创建一个拷贝函数:
自动类型转换应小心使用。同所有重载的运算符相比,它在减少代码方面是非常出色的,但不值得无缘无故地使用。