C++强制类型转换

发布于 2021-09-17  55 次阅读


1. C风格的强制转换

C风格的强制转换(Type Cast)容易理解,不管什么类型的转换都可以使用使用下面的方式.

TypeName b = (TypeName)a;

C++支持C风格的强制转换,但是C风格的强制转换可能带来一些隐患,让一些问题难以察觉.所以C++提供了一组可以用在不同场合的强制转换的函数.

2. C++ 四种强制转换类型函数

2.1 const_cast

这个转换是专门去除or添加引用或指针的常量性的:

const int c_val = 233;  //声明为常量类型
int &use_val = const_cast<int&>(c_val); //使用去const 引用
int *ptr_val = const_cast<int*>(&c_val);//使用去const 指针

使用这个函数可以将一个常量指针或常量引用转成非常量的指针或引用。但这里只是改变了标志使其符合语法规则,如果对转换后的对象进行修改,结果是未定义的!!

use_val = 666;  //未定义行为
*ptr_val = 110; //未定义行为

所以我们要避免对转换后的指针进行修改操作,这个类型转换主要是用于某些函数的参数,要求的是非常量指针,但保证对其不会进行修改操作。此时使用强制转换使参数类型合法化。

void print(int* pt) { printf(*pt); } //函数接收一个非const指针,但内部不修改,只是访问

print(const_cast<int*>(&c_val));  //无法直接把一个const指针传递给非const指针,需要类型转换

此外还能用来添加or移除变量的volatile标志,但同样只是改变标志使其符合语法规则。指向的变量依然符合原先的语义。

2.2 static_cast

  • static_cast 作用和C语言风格强制转换的效果基本一样,由于没有运行时类型检查来保证转换的安全性,所以这类型的强制转换和C语言风格的强制转换都有安全隐患。
  • 用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。注意:进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的。
  • 用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性需要开发者来维护。
  • static_cast不能转换掉原有类型的const、volatile、或者 __unaligned属性。(前两种可以使用const_cast 来去除)
  • 在c++ primer 中说道:c++ 的任何的隐式转换都是使用 static_cast 来实现

2.3 dynamic_cast

这个函数用于基类指针(引用)和子类指针 (引用) 的互相转换,并提供运行时类型检查:

当转换不成功的时候就返回一个空指针,不成功的条件如下

  • 两个没有继承关系的类互相转换
  • 指向基类的指针转为子类类型的指针
class Base{
... //code
}

class A : public Base {
... //code
}

class B{
... //code
}

Base * base = new Base();
A * base2a = dynamic_cast<A*>(base); //nullptr,指向基类的指针转为子类

A * a = new A();
Base * a2base = dynamic_cast<Base*>(a); //success

B * b = new B();
A * b2a = dynamic_cast<A*>(b); //nullptr,无继承关系

B * base2b = dynamic_cast<Base*>(b); //nullptr,无继承关系

2.4 reinterpret_cast

reinterpret_cast是强制类型转换符用来处理无关类型转换的,通常为操作数的位模式提供较低层次的重新解释!但是他仅仅是重新解释了给出的对象的比特模型,并没有进行二进制的转换!

实际的例子是哈希函数,传入一个对象的地址,根据地址计算它的哈希值:

unsigned short Hash( void *p ) {
	unsigned int val = reinterpret_cast<unsigned int>( p );
	return ( unsigned short )( val ^ (val >> 16));
}

指针就是一个地址,这里使用强制转换,把指针解释成一个无符号整型,然后进行计算。对于底层的二进制数据没有进行任何的更改。


当其他人都认为你要鸽的时候,你鸽了,亦是一种不鸽