C++经验之强制类型转换

版权声明:本文为博主原创文章,转载时请标明来源。 https://blog.csdn.net/aiwangtingyun/article/details/86577467

C风格强制转换(旧式转换)

在C中存在数据类型的转换,比如字符型转换为整型,浮点型转换为整型,void指针转换为其它类型的指针,其形式为:

// C语言风格转型
(T)experssion		// 将expression强转为类型T
// 函数形式转型
T(experssion)		// 将expression强转为类型T

这两种风格形式都一样,没什么区别,只是小括号的位置不同而已!


C++风格转换(新式转换)

为了体现C++的“类型安全”的特性,C++提供了4种不同的类型转换操作符:

const_cast<T>( experssion )			// 常量转换
dynamic_cast<T>( experssion )		// 动态转换
reinterpret_cast<T>( experssion )	// 重解释转换
static_cast<T>( experssion )		// 静态转换

const_cast

const_cast虽然叫做常量转换,但却不是为变量添加常量性而是去除常量性(这是要牢记的),考虑下面这种情况:

const char *pc = &ch;				// 定义常量指针
char *p = const_cast<char *>pc;		// 正确:可以通过p来改写指向的对象

一般来说,我们通过const限定符修饰对象达到使对象值不能被修改保护对象的目的,而const_cast则是为了实现去掉这种不能修改的常量特性,但需要注意:const_cast不是用于去除变量的常量性,而是去除指向常量对象的指针或引用的常量性,其去除常量性的对象必须为指针或引用,考虑下面的例子:

const int a = 1;
int b = const_cast<int>(a);			// 编译错误,转换对象必须为指针或引用

所以总结const_cast的作用为:

1、去除对象的const属性,这里顺便提一下:const_cast也可以去除volatile属性;
2、常量指针被转化成非常量指针,并且仍然指向原来的对象;
3、常量引用被转换成非常量引用,并且仍然指向原来的对象;


static_cast

静态转换static_cast一般用于数据类型的强制转换,强制将一种数据类型转换为另一种数据类型,只要是具有明确定义的类型转换都可以,比如将浮点型转换为整型:

double b = 10.4;				
int i = static_cast<int>(b);		// 存在精度损失

将double转换为int属于是较大类型转换为较小类型,如果直接将double赋值给int,编译器会给出警告,但是,使用了强制类型转换就意味着告诉编译器或读者:我们知道并且不在乎潜在的精度损失。

static_cast也可以实现编译器无法自动转换的类型转换,比如,将void指针转为其它类型的指针:

void *p = &d;							// 任何对象地址都可以存入到void*
double *dp = static_cast<double *>(p);	// 正确:可以将void*转回初始的指针类型

总结static_cast用法为:

1、用于基本数据类型之间的转换,如把int转换成char。这种转换的安全也要开发人员来保证
2、把空指针转换成目标类型的指针
3、把任何类型的表达式转换为void类型
4、用于类层次结构中基类和派生类之间指针或引用的转换
①进行上行转换(把派生类的指针或引用转换成基类表示)是安全的
②进行下行转换(把基类的指针或引用转换为派生类表示)由于没有动态类型检查,所以是不安全的

注意:static_cast不能转换掉expression的const、volitale或者__unaligned属性。


reinterpret_cast

reinterpret_cast为对象的位模式提供重新解释(强制转换过程仅仅只是比特位的拷贝),比如:改变指针或引用的类型、将指针或引用转换为足够长的(具体看操作系统)整型,再将整型转换为指针或引用类型。考虑下面的例子:

int *ip = &i;
char *pc = reinterpret_cast<char *>(ip);

ip为整型指针,要想把它转换为字符指针需要告诉编译器:我要重新解释该整型指针为字符指针。有一点必须注意原先整型指针所指对象是个整型,重新解释为字符使用时,其行为是未定义的,这一点需要程序员自己负责。

总结reinterpret_cast用法为:

reinterpret_cast<type_id> (expression)

①type-id必须是一个指针、引用、算术类型、函数指针或者成员指针。
②它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针,也就是它的转换原理:先把一个指针转换成一个整数,再把该整数转换成原类型的指针


dynamic_cast

其它三种强制类型转换都是编译时就完成的,而动态转换dynamic_cast则是运行时处理的,并且在运行的时候会进行类型检查。需要注意的是,动态类型转换不能用于内置数据类型转换(需要的话使用static_cast),而动态转换要转换成功的话其基类必须有虚函数,否则编译器无法编译通过,想一想,多态的实现手段是基类指针指向派生类对象,只有在基类的成员函数为虚函数而派生类重写该虚函数时才能使用基类指针调用派生类对象的成员函数。

编译器之所以会检查基类是否有虚函数的原因是:只有类中存在虚函数,才说明它有想要让基类指针或引用指向派生类对象的情况,此时转换才有意义。具体实现如下:

class Base { ... };							// 基类
class Derived : public Base { ... };		// 派生类
Base *bp = new Derived;						// 基类指针指向派生类对象
Derived *dp = dynamic_cast<Derived *>(bp);	// 动态类型转换

值得注意的是上述动态类型转换,如果基类指针bp指向的是派生类对象,此时转换后的操作是安全的,如果不是的话,动态类型转换失败返回的结果为0(编译器会帮你检查)。

猜你喜欢

转载自blog.csdn.net/aiwangtingyun/article/details/86577467