zoukankan      html  css  js  c++  java
  • 5. 对定制的“类型转换函数”保持警觉

    C++中允许编译器在不同类型中执行隐式转化,例如默默地将char转化为int,将short转化为double等等,这些是语言提供的。现在当你写自己的类型时,你可以选择是否提供某些函数,供编译器用作隐式类型转化之用。如定义一个类类型,是否允许其它类型转化为此类类型,我们可以操控的。

    可以通过两种函数允许编译器执行这样的隐式转化:单自变量constructor 和隐式类型转化操作符。

    单自变量constructor :指的是以单一自变量成功调用的constructor,这样的constructor可能只有一个单一参数,也可能有多个参数,而其他参数都有默认值。如下面两个例子:

    class CName{
    
        public:
    
            CName(const string& s);      //ctor声明时只有一个自变量
    
        //...
    
    };
    
    
    
    class CRational{
    
        public:
    
           CRational(int numerator = 0, int denominator = 1);      //ctor声明时有两个自变量,但其他有默认值
    
        //...
    
    };
    
    
    
    //上面的ctor可以用来作为隐式类型转化函数
    
    CName stu = "hazirguo";         //可以将string类型转化为CName类型
    
    CRational doub = 3;             //可以将int 类型转化为CRational类型

    隐式类型转化操作符:这是一个成员函数,由关键词operator 后加上一个类型名称。如下例:

    class CRational{
    
        public:
    
            CRational(int numerator, int denominator);
    
            operator double() const                       //可以完成将CRational类转化为double类型
    
            {   return numerator * 1.0 / denominator;   }
    
            //...
    
    };
    
    //下面的代码会调用上面的转化函数
    

    CRational r(1, 2); // r = 1/2

    double d = 0.5 * r; // 将r转化为double,再相乘

    但是,最好不要提供任何类型转化函数!!!因为在你从未预期的情况下,此类函数就可能被调用,而结果显然不是你想要的,但是此类错误往往是很难调试的。分别举例说明之:

    例一:

    class CArray{
    
    public:
    
    	CArray(int lowBound, int highBound);       //两个参数的ctor,不可能作为隐式转化函数
    
    	CArray(int size);                          //单变量ctor,可能作为隐式转化函数使用
    
    	int operator[] (int index);
    
    	//...
    
    };
    
    bool operator == (const CArray& lhs, const CArray& rhs);       //重载 == 函数
    
    CArray a(10);
    
    CArray b(10);
    
    for (int i = 0; i < 10; i++)
    
    {
    
    	if (a == b[i])           //原意是a[i] == b[i],但此处编译器却为报错
    
    	{   /* do something when a[i]==b[i]  */   }   // (***)
    
             else
    
             {  /* ...  */     }
    
    }

    之所以没有报错的原因是:a == b[i]的一边是CArray型,一边是int型,而重载operator == 函数带有两个CArray型参数,编译器试图将int转化为CArray型是行的通的,

    因为CArray有个单自变量的ctor,可以将int转化为CArray型。但很显然,这样的话,结果不是我们预期的那样!

    解决的方法:只要将ctor声明为explicit就行了,编译器便不能因隐式转化的需要调用它们。不过显示类型转化仍然是可行的:

    class CArray{
    
    public:
    
       //...
    
       explicit CArray(int size);      //这里使用了关键字explicit
    
       //...
    
    };
    
    
    
    CArray a(10);
    
    CArray b(10);
    
    
    
    if (a == b[i])         //error! 无法将int隐式转化为CArray型
    
    if (a == static_cast<CArray> (b[i]))          //right!显示转化仍然可行

    例二:

    class CRational{
    
        public:
    
            CRational(int numerator, int denominator);
    
            operator double() const                       //可以完成将CRational类转化为double类型
    
             {   return numerator * 1.0 / denominator;   }
    
            //...
    
    };
    
    //
    
    CRational r(1, 2);
    
    cout << r;          //原意输出1/2,但却输出了0.5

    上面程序并没有定义operator << 可以接受CRational,但编译器却没有报错,却输出了一个double型的数0.5。原因在于,编译器会想尽各种方法让函数转化成功,本例中只要调用CRational::operator double 即可将CRational转化为double型,于是上述代码将r以非分数形式输出。显然,这也不是我们想要的结果!!

    解决方法:以功能对等的另一个函数取代类型转化操作符。本例中,为了将CRational转化为double,不妨以一个名为asDouble的函数取代operator double:

    class CRational{
    
        public:
    
            CRational(int numerator, int denominator);
    
            double asDouble() const ;        //将CRational 转化为double
    
    };
    
    
    
    CRational r(1, 2);
    
    cout << r;            //error! CRational 没有operator <<
    
    cout << r.asDouble();      //right!

    小结: 一般而言,愈有经验的C++程序员愈可能避免使用类型转化操作符。

    参考文献: 《More Effective C++ 35个改善编程与设计的有效方法 中文版
  • 相关阅读:
    开发工具 编程风格
    WinServer2003 Computer Browser服务每隔一段时间自动关闭问题解决方法
    VSS 无法与服务器建立连接 以及与服务器断开连接
    VSS 部署
    db2 服务器启动项目
    Sublime Text 2 编辑器实用技巧
    WdatePicker日历控件使用方法
    02.微博账号注册
    01.微博三方登录原理讲解
    3.celery发送短信接口
  • 原文地址:https://www.cnblogs.com/hazir/p/2450561.html
Copyright © 2011-2022 走看看