一、隐式类型转换
定义:当用一个位置需要一个B类型时,使用A类型代替,而A类型又能自动转换为B类型,那么这个转换过程则称为隐式转换。
二、标准隐式转换
也就是编译器内置的类型转换, 比如数组退化成指针,函数转换成函数指针,特定语境下要求的转换(if里要求bool类型的值),整数类型提升,数值转换,数据类型指针到void指针的转换,nullptr_t到数据类型指针的转换等。
三、自定义类型转换
所谓自定义类型转换,是相对于标准隐式转换而言的,需要用户自己实现,分为转换构造函数和自定义类型转换函数。
3.1 转换构造函数
当类A存在形如A(B)的构造函数时(B可能是内置类型也有可能是自定义类型),则会发生B类型向A类型的隐式转换,如下方的int类型向Number类型的转换。
class Number
{
public:
Number(int a): m_val(a){}
private:
int m_val;
};
Number test(const Number &) {
return 1; //隐式转换为Number
}
int main()
{
test(1); //隐式转换为Number
Number x = 1; //隐式转换为Number
}
风险:可读性较差
抑制转换构造函数
为了解决这一风险,C++提供了explicit关键字修饰构造函数,从而抑制转换构造函数的行为,使得只能显示类型转换或直接构造。
Number y = Number(1);
test(static_cast<Number>(1));
3.2 自定义类型的隐式转换
类似于构造函数,在类A中形如
operator B()
的成员函数,意味着可以将A隐式转换为A类型。
class A {};
class B {
public:
B(const A &) {}
operator A () { return A(); }
operator bool() { return false; }
};
void testA(const A &)
{
}
int main()
{
A a;
B b = a;
testA(b); //自定义类型转换
std::cout << b + 3 <<std::endl;
}
如上面的例子,20行的testA函数需要A类型的参数,这里传入了b也可以完成调用,是因为发生了隐式类型转换。
风险:
上面的testA()函数可能还看不到什么危害较大的风险。但是对于operator bool则会带来没有意义的操作,如21行可以将一个B类型和整型相加,这是没有任何意义的。
抑制自定义类型的隐式转换
从C++11开始,将构造函数的explicit修饰词扩展到自定义类型转换函数上,以抑制其引起的隐式转换。
explicit operator A () { return A(); }
explicit operator bool() { return false; }
抑制之后,仅仅允许直接初始化和显示类型转换。
bool c(b);
A d = static_cast<A>(b);