【C++11】显式转换操作符

来源:互联网 发布:python核心编程知乎 编辑:程序博客网 时间:2024/05/21 10:38
转: https://my.oschina.net/jthmath/blog/511895
隐式类型转换是C++的一个既好又坏的特性。它给人以方便,但可能造成一些十分隐晦的错误。
类型转换提供了一个类型向另一个类型的构造。

class X{public:    operator int() const noexcept    {        return 42;    }};void Func(int) {}int wmain(){    X x0;    X x1;    Func(x0);    Func(x1);    int n = x0 + x1;    std::cout << n << std::endl; // 84    return 0;}

上面的代码中,X可以隐式地转换为int,于是函数Func可以接受X类型的参数,x0与x1也可以用+来做运算。

在实际的编程工作中,一个更常见的例子是,我们自己定义的字符串类(记为String)重载了operator const wchar_t*():

class String{public:    operator const wchar_t*() const noexcept    {        // 函数体    }};

从而,如果一个函数需要const wchar_t*类型的参数,就可以直接传入一个String实例。


但是,重载类型转换也不是万无一失的。比如,重载operator bool()。

重载operator bool()所带来的问题比较多,以至于很多企业的编码规范中,都不提倡甚至禁止重载operator bool()。

由于bool属于算数类型,所以重载了operator bool()的类的实例可以被用在任何需要算术类型的上下文中。

class Y{private:    int m_;public:    explicit Y(int m) :m_{ m } {}    operator bool() const noexcept    {        return (m_ != 0);    }};int wmain(){    Y y0{ 12 };    Y y1{ 25 };    auto n = y0 + y1; // !!!    std::cout << n << std::endl;    return 0;}

毫无意义的y0 + y1竟然(无警告地)编译通过,而且还通过+产生了一个int,这实在不合理。可能程序作者想要的是Y(38),更可能的是后来维护代码的人根本无法知道原作者想干什么。随着代码的规模变大,这些细微的隐患会越埋越深,或许,将来花费两天时间找到的BUG就是由它引起的。


为了防止这样的异常情况,C++11引入了显式的类型转换运算符

class X{public:    explicit operator int() const noexcept    {        return 42;    }};void Func(int) {}int wmain(){    X x0;    Func(x0); // 错误,不存在从 X 到 int 的(隐式)转换    int y = x0; // 错误,不存在从 X 到 int 的(隐式)转换    Func((int)x0); // 正确1    Func(int(x0)); // 正确2    Func(static_cast<int>(x0)); // 正确3    return 0;}

用explicit修饰的类型转换运算符,则相应的类型转换必须显式地进行。C式(正确1),函数(正确2),static_cast(正确3)都行。


但是,显式的类型转换有一个例外。如果表达式被用作条件,那么显式的operator bool()也可以隐式地进行(仅限转换到bool)。“被用作条件”即:

  • if、while及do语句的条件部分;

  • for语句头的条件表达式;

  • 逻辑非运算符(!)、逻辑或运算符(||)、逻辑与运算符(&&)的运算对象;

  • 条件运算符(x ? y : z)的条件表达式。

由于转换到bool一般被用作条件,所以operator bool()一般用explicit来修饰。

class K{public:    explicit operator bool() const noexcept    {        return false;    }};int wmain(){    K k0;    if (k0) // 正确    {        std::cout << "qwer" << std::endl;    }    else    {        std::cout << "zxcv" << std::endl;    }    return 0;}
0 0
原创粉丝点击