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

隐式类型转换是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*():spa

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

从而,若是一个函数须要const wchar_t*类型的参数,就能够直接传入一个String实例。code


可是,重载类型转换也不是万无一失的。好比,重载operator bool()。对象

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

因为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就是由它引发的。it


为了防止这样的异常状况,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;
}
相关文章
相关标签/搜索