建议17:提防隐式转换带来的麻烦(2)
使用具名转换函数
来看一段代码:
- class Rational
- {
- public:
- Rational(int numerator = 0, int denominator = 1)
- :m_num(numerator),m_den(denominator){}
-
- operator double() const
- {
- return ((double)m_num/(double)m_den);
- }
- private:
- int m_num;
- int m_den;
- };
-
- Rational r(1,2);
- cout<<r<<endl;
上面代码的本意是打印类似n/m的形式,可是结果输出的却是0.5。问题出现在哪里?当调用operator<<时,编译器会发现没有合适的函数存在,所以它就试图找到一个合适的隐式类型转换顺序,以使函数得到正常调用。本来程序中并不存在将Rational转为其他类型的转换规则,但是Rational::operator double函数告诉编译器Rational类型可以转换为double类型,所以就有了上述结果的出现。为了避免此类问题的出现,建议使用非C/C++(www.cppentry.com)关键字的具名函数,代码如下所示:- class Rational
- {
- public:
- Rational(int numerator = 0, int denominator = 1);
- operator as_double() const;
- private:
- int m_num;
- int m_den;
- };
-
- Rational r(1,2);
- cout<<r<<endl; // 提示无operator<<Rational重载函数
使用 explicit 限制的构造函数
这种方式针对的是具有一个单参数构造函数的用户自定义类型。代码如下所示:
- class Widget
- {
- public:
- Widget( unsigned int factor);
- Widget( const char* name, const Widget* other = NULL);
- };
上述代码片段中,用户自定义类型Widget的构造函数可以是一个参数,也可以是两个参数。具有一个参数时,其参数类型可以是unsigned int,亦可以是char*。所以这两种类型的数据均可以隐式地转换为Widget类型。控制这种隐式转换的方法很简单:为单参数的构造函数加上explicit关键字:- class Widget
- {
- explicit Widget(unsigned int factor);
- explicit Widget(const char* name, const Widget* other = NULL);
- };
请记住:
提防隐式转换所带来的微妙问题,尽量控制隐式转换的发生;通常采用的方式包括:(1)使用非C/C++(www.cppentry.com)关键字的具名函数,用operator as_T()替换operato T()(T为C++(www.cppentry.com)数据类型)。(2)为单参数的构造函数加上explicit关键字。