C++面向对象程序设计
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.6 类型转换

类型转换就是将一种数据类型转换为另一种数据类型。在同一个算术表达式中,若出现了两种以上的不同数据类型,就会先进行数据类型转换,再计算表达式的值。例如:

cout<<34+21.45+'a'<<endl;

在此语句的算术表达式中,出现了3种数据类型:34是int类型,21.45是double类型,'a'是char类型。运算的过程如下:首先将34转换成double类型的34.00,再完成34.00+21.45的运算,得到double类型的结果55.45,然后将char型的'a'转换成double类型的97.00,再计算55.45+97.00,最后的结果是double类型的152.45。

类型转换可分为隐式转换和显式转换。在C++中,类型转换经常发生在算术表达式计算、函数的参数传递、函数返回值及赋值语句中。

2.6.1 隐式类型转换

C++定义了一套标准数据类型转换的规则,如图2-2所示。在必要时,C++会用这套转换规则在程序员不参与的情况下自动进行数据类型的转换,称为隐式类型转换。

图2-2 C++隐式类型转换方法

在以下4种典型情况下,都会发生隐式类型转换。

① 在出现了多种数据类型的算术表达式中。转换的总原则是窄数据类型(占用存储空间少的类型)向宽数据类型转换(占用存储空间多的类型),具体情况如图2-2所示。

前面介绍的“34+21.45+'a'”计算过程中的类型转换就属于这种情况。

② 将一种类型的数据赋值给另一种类型的变量,会发生隐式类型转换,把赋值句右边的表达式结果转换成赋值句左边变量的类型。例如:

int a=2;
float b=3.4;
double c=2.2;
b=a;       //将a的值2转换成float型的2.0再赋给b
a=c;       //将c的值2.2转换成int型的2赋给a

由于宽类型数据所占的存储空间比窄类型多,因此窄类型向宽类型转换不会有什么问题,而宽类型数据转换成窄类型则常会发生精度损失,是不安全的。C++常采用截取方法进行宽类型向窄类型的转换,即从宽类型中截取与窄类型大小相同的存储区域作为转换的结果,而宽类型中多出的字节就丢掉了。例如“a=c”,C++将截取c的整数部分并赋值给a,至于c的小数部分就丢掉了,所以a的最终结果是2。

③ 在函数调用中,若实参表达式与形式参数的类型不相符,则把实参的类型转换成形参的类型;在函数返回时,若函数返回表达式的值与函数声明中的返回类型不同,则把表达式结果转换成函数返回类型。

float min(int a,int b) {
    return a<b?a:b;
}

return语句中的表达式结果为int,与min()函数返回类型float不同,因此会发生类型转换,将“a<b?a:b”的结果转换float类型后再返回给min()函数。

假设对上面的函数min(),存在如下函数调用:

int a=2;
float b=3.4;
int x=min(b,a+3.5);

由于min()的形式参数是int,所以在“min(b,a+3.5)”调用中,将把b的值3.4从float类型转换成int类型的3,“a+3.5”的结果5.5也被转换成int类型的5,再传送给相应的形式参数。

2.6.2 显式类型转换

把一种数据类型强制转换为另一种类型就称为显式转换,也称为强制转换。形式如下:

(type) exp

或者

type (exp)

其中,type是目标类型,exp是要进行类型转换的表达式,强制转换把exp转换成type型。第一种是C语言支持的类型转换方式,它在C++语言中同样可用;第二种是只有C++语言才允许使用的类型转换方式,在C程序中不可用。例如:

int a=4;
float c=(float)a;  //C语言中使用的类型转换方式,在C++中仍可用,结果为4.0
a=int(8.8);    //只能用于C++语言而不能用于C语言的类型转换方式,结果为8

在C++标准中,还有4个强制类型转换运算符:static_cast,dynamic_cast,const_cast和reinterpret_cast。其用法如下:

x_cast <type> (exp)

其中,x_cast代表强制类型,可以是static_cast、dynamic_cast、const_cast或reinterpret_cast之一,type是强制转换后的类型,exp是要转换类型的表达式。

static_cast是静态强制转换,能够实现任何标准类型之间的转换,如从整型到枚举类型,从浮点型到整型之间的转换等。事实上,凡是隐式转换能够实现的类型转换,static_cast都能够实现。例如:

char p='d';
int x=static_cast<int > (p);      //将p转换成int,x=100
double y=static_cast <double> (54); //将54从int型转换成double型

const_cast是常量强制转换,用于强制转换const或volatile(可变)的数据,它转换前后的数据类型必须相同,主要用来在运算时暂时删除数据的const限制。

例2-8】 利用const_cast转换去掉引用的const限制。

//Eg2-8.cpp
#include<iostream.h>
void sqr(const &x) {
    const_cast<int &>(x)=x*x;  //L1 去掉了x的const限制,否则不能修改x
    //x=x*x;     //L2 错误,x为const,不能被修改
}
void main(){
    int a=5;
    const int b=5;
    sqr(a);       //L3 通过引用将a改为25
    cout<<a<<endl;    //L4 输出25
    sqr(b);   //L5 由于b为const,sqr对其修改无效
    cout<<b<<endl;  //L6 输出5
}

函数sqr()的参数x是常量引用,不能通过它修改实参的值,但是语句“const_cast<int &>(x);”在执行时暂时去掉了x的const限制,将其结果改为x*x,本语句执行后,x即恢复为const,因此语句L2是错误的。语句L5通过sqr()的形参x修改了实参b单元中的值为25,但b是const,在函数结束时,此修改即无效,b恢复原来的const值5。

reinterpret_cast是重解释强制转换,能够完成互不相关的数据类型之间的转换,如将整型转换成指针,或把一个指针转换成与之不相关的另一种类型的指针。

int i;
char *c="try fly";
i=reinterpret_cast<int >(c);

reinterpret_cast 其实是按强制转换所指定的类型对要转换数据对应的内存区域进行重新定义。在本例中,reinterpret_cast将c对应的内存区域(一个内存地址,因为c是指针)重新定义为一个整数,这种转换在这里并没有多大的意义。

dynamic_cast是动态强制转换,主要用于基类和派生类对象之间的指针转换,以实现多态。与其他几个强制类型转换运算符不同的是,dynamic_cast所完成的类型转换是在程序运行时刻实现的,而其他类型的强制转换在编译时就完成了。