1.隐式类型转换的问题

隐式类型转换是 C++ 一个让人又爱又恨的特性,使用方便,但可能会降低代码可读性,甚至会造成一些十分隐晦的错误。

#include <iostream>
using namespace std;

class MyInt {
public:
	// 单参构造函数
	explicit MyInt(int value) :_value(value)
	{}

	// 类型转换操作符
	operator bool() const noexcept {
		return _value != 0;
	}

	// 加运算符重载
	MyInt& operator+(const MyInt& right) {
		_value += right.getValue();
		return *this;
	}

	int getValue() const {
		return _value;
	}
private:
	int _value;
};

int main() {
	MyInt myInt1(1);
	MyInt myInt2(2);
	cout << "myInt1+myInt2=" << myInt1 + myInt2 << endl;
	return 0;
} 

程序编译运行输出:

myInt1+myInt2=1

虽然程序编译运行没有什么问题,但是两个 MyInt 对象相加的结果并不是我们期望的数值 3,而是 1,导致这种隐晦错误的原因是在两个 MyInt 对象相加后,结果对象 myInt1 由于没有合适的输出操作符函数 operator<<() 将其输出,被隐式地转换为 bool 类型,导致输出数值为 1。随着项目代码规模变大,这种由隐式类型转换导致的隐晦错误会越埋越深,越来越难以发现。

2.显示类型转换的实现

为了阻止容易导致隐晦错误的隐式类型转换,C++11引入了 explicit 关键字作用于自定义的类型转换操作符,禁止隐式类型转换。其用法类似于explicit 作用于单参构造函数来避免单参数构造函数被隐式调用造成的隐式类型转换。

// 类型转换操作符
explicit operator bool() const noexcept {
	return _value != 0;
}

cout << "myInt1+myInt2=" << myInt1 + myInt2 << endl; //编译出错

当使用 explicit 关键字修饰 bool 类型转换操作符时,隐式类型转换将会被阻止,进而引起上面的编译错误,将潜在的隐晦错误暴露于编译阶段,让错误得以提前发现,提前解决。

注意,显式类型转换有一个例外。如果表达式被用作条件,仅限转换到bool,那么显式的 operator bool() 也可以隐式地进行。“被用作条件”指出现在以下语句:
(1)if、while 及 do 语句的条件部分;
(2)for 语句头的条件表达式;
(3)逻辑非运算符(!)、逻辑或运算符(||)、逻辑与运算符(&&)的运算对象;
(4)条件运算符(x ? y : z)的条件表达式。

由于转换到 bool 一般被用作条件,而不应该被用于数值运算,所以operator bool() 一般用 explicit 来修饰。


参考文献

深入理解C++11[M].C3.4显示转换操作符.P89-P92
【C++11】显式转换操作符

Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐