C语言传统的类型转换
C方式的类型转换方式:(Type) (Expression)
或Type (Expression)
,后者比较古老。C风格的强制类型转换容易出问题,比较粗暴,如:
typedef void(PF)(int);
struct Point {
int x; int y;
};
int v = 0x12345;
PF* pf = (PF*)v; //转换方式过于粗暴,试问:能否保证变量v作为地址是否一定指向PF*类型的函数入口
char c = char(v); //char类型的数据取值范围有限,能否保证整型数v按照char方式转换一定会在其值域中
Point* p = (Point*)v; //同样,无法保证将v作为Point*类别的地址值,该地址值一定是一个Point结构体对象的地址
C方式强制类型转换存在的问题:
-
过于粗暴——
任意类型之间都可以进行转换,编译器很难判断其正确性
-
难于定位——
在源码中无法快速定位所有使用强制类型转换的语句
C++的新类型转换
C++将强制类型转换分为四种不同的类型,分别是static_cast
、const_cast
、dynamic_cast
、reinterpret_cast
,其用法为xxx_cast<Type>(Expression)
。
static_cast
使用要点:
- 用于基本类型之间的转换;(基本类型:int、float、double……)
- 不能用于基本类型指针间的转换;
- 用于有继承关系类对象之间的转换和类指针之间的转换;
const_cast
使用要点:
- 用于去除变量的只读属性;
- 强制转换的目标类型必须是指针或引用;
reinterpret_cast
使用要点:
- 用于指针类型间的强制转换;
- 用于整数和指针类型间的强制转换;
dynamic_cast
使用要点:
- 用于有继承关系的类指针间的转换;
- 用于有交叉关系的类指针间的转换;
- 具有类型检查的功能;
- 需要虚函数的支持;
补充说明:
-
使用dynamic_cast转换如果不成功,将得到空指针,成功将返回指向类对象的指针或引用;
-
dynamic_cast是运行时处理的,而其他三种都是编译时处理的;
-
在类族中进行上行转换时,dynamic_cast和static_cast的效果是一样的,但在下行转换时,dynamic_cast具有类型检查功能,比static_cast更安全。
-
上行转换:子类向父类转换(C++中的继承是全部接收,故父类的成员子类都具有,进行上行转换时一般不会有问题)
-
下行转换:父类向子类转换;
下行转换的成功与否与将要转换的类型有关,即「将要转换的类指针(或引用)所指向对象的实际类型」与「转换结果对象的类型」一定要相同,否则转换失败。
-
代码演示
#include <iostream>
using namespace std;
void static_cast_demo() {
int i = 0x12345;
char c = 'c';
int* pi = &i;
char* pc = &c;
c = static_cast<char>(i);
//pc = static_cast<char*>(pi); //Error,static_cast不能转换基本类型指针
cout << "static_cast affect i to c:" << i << " to " << c << endl;
}
void const_cast_demo() {
const int& j = 1;
int& k = const_cast<int&>(j);
const int x = 2; //在C++中进入符号表,但仍按照C语言方式分配存储空间
int& y = const_cast<int&>(x); //相当于将x的内存空间重新起了一个别名,别名的使用方式不在有只读属性限定
//int z = const_cast<int>(x); //Error,const_cast只能用于指针或引用类型的转换
k = 5;
cout << "k=" << k << ",j=" << j << endl;
y = 8;
cout << "x=" << x << ",y=" << y << endl; //由于x进入符号表,则从符号表中取用的时候仍为最初的值,而y是从分配的空间中读取值的
cout << "&x=" << &x << ",&y" << &y << endl;
}
void reinterpret_cast_demo() {
int i = 0; char c = 'c';
int* pi = &i; char* pc = &c;
pc = reinterpret_cast<char*>(pi);
cout << "pc:" << (void*)pc << endl;//int*到char*之间的指针类型转换,由于cout输出字符指针是当作字符串的,所以用void*告诉程序按指针方式输出
pi = reinterpret_cast<int*>(&c);
cout << "pi:" << pi << endl;//不同指针类型之间的强制类型转换
pi = reinterpret_cast<int*>(i); //整数和指针之间的强制类型转换
//c = reinterpret_cast<char>(i); //不支持基本类型之间的转换
cout << "pi<int to int*>:" << pi << endl;
}
int main() {
static_cast_demo();
const_cast_demo();
reinterpret_cast_demo();
}