条款27 尽量少做转型动作

隐式转换

在谈及显式转换之前,先简单说说隐式转换。

int ival = 0;
ival = 3.541 + 3;  //doubl向int转换会丢失精度,编译器会警告:“=”从double到int转换可能会丢失数据,结果ival等于6

         整数3被转换为double类型,然后执行浮点类型加法操作,得double类型结果6.541,然后将double类型值赋值给int类型变量ival。在赋值中不可能改变左操作数的类型,因此左操作数类型占主导地位。如果赋值操作的左右操作数类型不同,则右操作数会被转换为左操作数的类型。本例中,double向int转换自动按截尾形式进行,小数部分被舍弃,于是6.541变为6,然后赋给ival。


何时发生隐式类型转换?

(1)在混合类型的表达式中

        如上提到的例子那样。

(2)用作条件的表达式被转换为bool类型

int ival
if (ival)  //ival转换为bool
while (cin) //cin转换为bool
条件操作符(?:)的第一个表达式、逻辑非(!)、逻辑与(&&)、逻辑或(||)的操作数都是条件表达式;

出现在if、while、for和do while语句中的同样都是条件表达式。

(3)用一表达式初始化某个变量或将一表达式赋值给某个变量,则该表达式被转换为该变量的类型

int ival = 4.33;  //3.14转换为int
int *p;
p = 0;    //int的0转为int *类型的null指针

算术转换

算术转换定义了一个转换层次,规定了操作数应该按什么层次转换为表达式章最宽的类型。转换规则要确保计算值的精度。

例如整型提升:对于所有比int小的整型,包括char、singed char、unsigned char、short、unsigned short,如果该类型所有可能值都包括在int内,它们都被提升为int型,否则,它们会被提升为unsigned int。如果将bool提升为int,则false转换为0,true转换为1。


指针转换

int ia[10];
int *p = ia; //将数组自动转换为指向第一个元素的指针

指向任意类型的指针都可以转换为void *类型;整数值常量0可转换为任意指针类型。


转换为const对象

使用非const对象初始化const对象的引用时,系统自动将非const对象转换为const对象。还可以将非const对象的地址(或非const指针)转换为指向相关const类型的指针:

int i;
const int ci = 0;
const int &j = i;  // 将非const的i转换为const int的引用
const int *p = &ci; //将ci的地址(非const)转换为const地址


由标准库类型定义的转换

string s;
while (cin >> s)

隐式使用了IO标准库定义的类型转换,求解表达式cin >> s,即读入cin,无论读入成功与否,该表达式结果都是cin,while循环条件应该为bool类型的值,而此时是istream类型值,于是其转换为bool类型。


接着说显式类型转换:

一、C风格旧式转型

(T) expression

T(expression)

两种形式并无差别,仅仅是小括号的摆放位置不同而已。


二、C++提供的四种新式转型

1、const_cast

去除表达式的常量性,是C++中唯一能去掉const属性的转型操作符,其他三种强制转换运用于去除const都会导致编译错误。类似地,除了添加或删除const特性,将const_cast用于执行其他任何类型转换,都会引起编译错误。

2、static_cast

用于强制隐式类型转换,编译器执行的任何类型的转换都可以由static_cast显示完成(除了将const转换为非const)。

double d = 99.0;
char ch = static_cast<char>(d); 
       当需要将一个较大的算术类型赋值给较小的类型时,使用强制类型转换很有用,此时强制类型告诉程序读者和编译器,我们知道并且不关心潜在的精度损失。如果隐式转换,编译器会警告,但是,这样的显式转换时,警告信息关闭。

如果编译器不提供自动转换,使用static_cast来执行转换也很有用:

double d = 2.2;
void *p = &d;
double *dp = static_cast<double *> (p); //static_cast将存放在void*中的指针强制转换为原来的指针类型。
static还可以将非const转换为const对象、将int转为double等;还能执行上述相反的转换:将void* 转为typed指针,将指向基类的指针转为指向派生类的指针。


3. dynamic_cast

        支持运行时识别指针或引用所指向的对象。主要用来执行“安全向下转型”,也就是用来决定某个对象是否归属于继承体系中某个类型。它将基类类型对象的引用或指针转换为同一继承层次中其他类型的引用或指针。

        与dynamic_cast一起使用的指针必须是有效的——它必须为0或指向一个对象。它是唯一无法由旧式语法执行的动作,也是唯一可能耗费重大运行成本的转型动作。和其他强制类型转换不同,它涉及运行时类型检查。如果绑定到引用或指针的对象不是目标类型的对象,则dynamic_cast会失败(转换失败时:如果是指针,结果为0;如果是引用,抛出一个bad_cast类型的异常)。

因此,dynamic_cast执行转换前要先验证转换是否有效,只有转换有效时,才进行转换。

<span style="font-size:12px;">//</span><span style="font-family:Helvetica,Arial,sans-serif;"><span style="font-size:12px;">指针
if (Derived *derivedPtr = dynamic_cast<Derived* > (basePtr)) {
       // 通过Derived类指针使用Derived对象
}else {
      // 使用基类对象
}

//引用
void f(const Base &b) {
       try {
              const Derived &d = dynamic_cast<const Derived&> (b);
              // use the Derived object to which b referred
       }catch (bad_cast) {
              //处理cast失败
      }
}
</span></span>

文章C++多态


4、reinterpret_cast

试图执行低级转型(例如将一个指向整数变量的指针转换为整数),实际动作及结果可能与编译器相关,因而降低了可移植性。


三、新式类型转换好处

第一,它们很容易在代码中被识别出来;第二,各转型动作的目标愈窄化,编译器愈可能诊断出错误的运用。例如,打算去除const属性,除非使用新式转换const_cast,否则无法通过编译。

未完成

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值