• 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个改善编程与设计的有效方法 中文版
  • 相关阅读:
    042.hiveLEFT SEMI JOIN 、 left anti join、inner join、full join
    032.hive rollup 、 with cube 、 grouping sets
    023.linuxshell抽取文本中某几行插入到另一个文
    041.mysql查询mysql元数据来格式化datax同步脚本,查询语句、拼接的json语句dataxmysql到hive
    33.hivecollect_set组合数组(数组内去重) 、array_contains 判断数组内是否又某个值返回布尔类型、concat_ws
    vue vant组件库 card组件 修改 thumb属性的图片 参数后不及时刷新解决
    idea 警告 The IDE is running low on memory and this might affect performance. Please consider increasing available heap. 解决
    尺子控件WinForm控件开发系列
    自定义形状按钮WinForm控件开发系列
    code ERESOLVE, ERESOLVE could not resolve
  • 原文地址:https://www.cnblogs.com/hazir/p/2450561.html
Copyright © 2020-2023  润新知