《深入理解C++11:C++ 11新特性解析与应用》——3.4 显式转换操作符

3.4 显式转换操作符

类别:库作者

在C++中,有个非常好也非常坏的特性,就是隐式类型转换。隐式类型转换的“自动性”可以让程序员免于层层构造类型。但也是由于它的自动性,会在一些程序员意想不到的地方出现严重的但不易被发现的错误。我们可以先看看代码清单3-26所示的这个例子。

image
image

在代码清单3-26中,声明了两个类型Rational1和Rational2。两者在代码上的区别不大,只不过Rational1的构造函数Rational1(int,int)没有explicit关键字修饰,这意味着该构造函数可以被隐式调用。因此,在定义变量r1_1的时候,字面量11就会成功地构造出Rational1(11, 1)这样的变量,Rational2却不能从字面量21中构造,这是因为其构造函数由于使用了关键字explicit修饰,禁止被隐式构造,因此会导致编译失败。相同的情况也出现在函数Display2上,由于字面量2不能隐式地构造出Rational2对象,因此表达式Display2(2)的编译同样无法通过。

这里虽然Display1(1)编译成功,不过如果不是结合了上面Rational1的定义,我们很容易在阅读代码的时候产生误解。按照习惯,程序员会误认为Display1是个打印整型数的函数。因此,使用了explicit这个关键字保证对象的显式构造在一些情况下都是必须的。

不过同样的机制并没有出现在自定义的类型转换符上。这就允许了一个逆向的过程,从自定义类型转向一个已知类型。这样虽然出现问题的几率远小于从已知类型构造自定义类型,不过有的时候,我们确实应该阻止会产生歧义的隐式转换。让我们来看看代码清单3-27所示的例子,该例子来源于C++11提案。

image

在代码清单3-27中,我们定义了一个指针模板类型Ptr。为了方便判断指针是否有效,我们为指针编写了自定义类型转换到bool类型的函数,这样一来,我们就可以通过if(p)这样的表达式来轻松地判断指针是否有效。不过这样的转换使得Ptr和Ptr两个指针的加法运算获得了语法上的允许。不过明显地,我们无法看出其语义上的意义。

在C++11中,标准将explicit的使用范围扩展到了自定义的类型转换操作符上,以支持所谓的“显式类型转换”。explicit关键字作用于类型转换操作符上,意味着只有在直接构造目标类型或显式类型转换的时候可以使用该类型。我们可以看看代码清单3-28所示的例子。

image
image

在代码清单3-28中,我们定义了两个类型ConvertTo和Convertable,Convertable定义了一个显式转换到ConvertTo类型的类型转换符。那么对于main中ConvertTo类型的ct变量而言,由于其直接初始化构造于Convertable变量c,所以可以编译通过。而做强制类型转换的ct3同样通过了编译。而ct2由于需要从c中拷贝构造,因而不能通过编译。此外,我们使用函数Func的时候,传入Convertable的变量c的也会导致参数的拷贝构造,因此也不能通过编译。

如果我们把该方法用于代码清单3-27中,可以发现我们预期的事情就发生了,if(p)可以通过编译,因为可以通过p直接构造出bool类型的变量。而p + pd这样的语句就无法通过编译了,这是由于全局的operator + 并不接受bool类型变量为参数,而Convertable也不能直接构造出适用于operator +的int类型的变量造成的(不过读者可以尝试一下使用p && pd这样的表达式,是能够通过编译的)。这样一来,程序的行为将更加良好。

可以看到,所谓显式类型转换并没完全禁止从源类型到目标类型的转换,不过由于此时拷贝构造和非显式类型转换不被允许,那么我们通常就不能通过赋值表达式或者函数参数的方式来产生这样一个目标类型。通常通过赋值表达式和函数参数进行的转换有可能是程序员的一时疏忽,而并非本意。那么使用了显式类型转换,这样的问题就会暴露出来,这也是我们需要显式转换符的一个重要原因。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值