More Effective C++ 条款5 对定制的"类型转换函数"保持警觉

1. C++ 允许内置数据类型之间(例如char和int,int和double等)进行隐式转换,对于内置类型之间的隐式转换有详细的规则,但不管怎样,这些都是语言提供的,既相对安全,我们又无法更改。

    对于自定义的类类型,隐式转换可以通过带单一自变量的构造函数和隐式类型转换操作符来实现(所谓"单一自变量指的是可以有多个参数,但除了第一个参数其他参数必须有默认实参)

2. 对于自定义类型的类型转换,有一个规则:”没有任何一个转换程序可以内含一个以上的‘用户定制转换行为’(亦即单自变量constructor亦即隐式类型转换操作符)“,也就是说,必要的时候编译器可以先进行内置类型之间的转换再调用带单自变量的构造函数或者先调用隐式类型转换操作符在进行内置类型之间的转换,但不可能连续进行两次用户定制的类型转换!

3. 隐式类型转换操作符type()意味着"需转则转,能转则转",也就是说,由于隐式转换过于灵活,某些情况下会导致类的设计者并不想出现的行为。例如设计者定义了一个有理数类Rational,同时定义了 operator int(),而没有定义<<,这种情况下如果对于语句"cout<<a;",编译器应该报错来提醒设计者,但实际上a会被转为int然后输出,这背离了设计者的初衷。

    因而最好不要定义隐式类型转换操作符,取而代之的方法是定义像"double toDouble()"的函数来执行类型转换的功能,虽然使用时有些许不便,但"可因为不再默默调用那些不打算调用的函数而获得弥补”。C++标准库中的string类从没有string到char* 的隐式类型转换操作符而采用c_str函数可能就是这个原因。

4. 对于单自变量的构造函数由于隐式的转换可能会出现更加隐蔽的错误,例如:对于一个Array<int>对象,以下代码可能是正确的:

1 Array<int> a;
2     Array<int> b;
3     for(int i=0;i<10;++i)
4         if(a=b[i]){}       //注意这里a的[]被落掉了,但是如果定义了只接受一个int值做参数的Array<int>的构造函数则改代码语法没错
View Code

    如果要去除单变量参数的构造函数的隐式类型转换特性,可以采用explict关键字声明,如果编译器不支持explict关键字,那么可以在自定义类与内置类型之间加一层只封装一个内置类型成员的类,并利用2规则实现同样的效果,如:

 1 class Array{
 2 public:
 3     class ArraySize{
 4     public:
 5         ArraySize(int numElements): theSize(numElements){}
 6     private:
 7         int theSize;
 8     };
 9     Array(ArraySize size);
10     ......
11 };
View Code

其中ArraySize被称为proxy(代理人) class(见条款30) ,这样唯一的缺点是在使用单一参数构造对象时中间加了一层转换,不过是值得的。

5. 总结允许编译器执行隐式转换弊大于利,所以非必要不要提供转换函数! 

posted @ 2015-06-26 03:07  Reasno  阅读(399)  评论(1编辑  收藏  举报