1. C方式的强制类型转换
(1)转换形式
①(Type)(Expression)
②Type(Expression) //老式的
【编程实验】粗暴的类型转换
#include <stdio.h> typedef void PF(int); struct Point { int x; int y; }; int main() { int v = 0x12345; PF* pf = (PF*)v; char c = char(v);//老式写法,很像函数调用 Point* p = (Point*)v; pf(5); printf("p->x = %d\n", p->x); printf("p->y = %d\n", p->y); return 0; }
(2)强制类型转换存在的问题
①过于粗暴:任意类型之间都可以进行转换,编译器很难判断其正确性
②难于定位:在源码中无法快速定位所有使用强制类型转换的语句
2. C++中新式的4种强制类型转换
(1)用法:xxx_cast(Type)(Expression)
(2)4种类型
类型 |
适用范围 |
举例 |
备注 |
static_cast |
①基本类型之间(可相互隐式转换) ②不能用于基本类型的指针之间(因为该类型的指针间不能互相隐式转换) ③类与子类对象之间的转换或类指针间转换。(子类对象可隐式转换为父类(单向,反之不行。指针类型也一样) |
int i = 0; char c = 'A';
int* pi = &i; char* pc = &c;
c = static_cast<char>(i); //ok,c =i 或 i=c(即可双向隐式转换)
//不能用于基本类型的指针间转换 pc = static_cast<char*>(pi);//oops,因为 pi不能隐式转换为pc |
①一般适用于两者间可隐式转换的类型(双向或单向均可)。 ②编译时检查,可用于非多态类指针间的转换,但不支持交叉转换。 ③在类层次间进行转换时,上行转换static_cast与dynamic_cast效果是一样的,但下行转换时dynamic_cast具有类型检查功能,比static_cast更安全。 |
const_cast |
目标类型(即尖括号内的类型)必须是指针或引用 |
//i有内存,因别名,每次从内存读取i const int& i = 1;//i为引用 int& a = const_cast<int&>(i);
const int j = 1; //为j分配内存,但不会去用它,从符号表中取j int& b = const_cast<int&>(j);
a = 5; //i==5;a==5; b = 3; //j==1,b==3; |
用于去除变量的const属性 |
reinterpret_cast |
①用于指针类型间 ②用于整数和指针类型之间 |
typedef void PF(int);
int i = 0; char c = 'c';
int* pi = reinterpret_cast<int*>(&c); //因为&c(char*类型)不能隐式转为pi。 char*pc = reinterpret_cast<char*>(&i);//&i不能隐式转为char*
PF*pf= reinterpret_cast<PF*>(0x12345678);
//以下错,要用static_cast c = reinterpret_cast<char>(i); //oops,因为i可隐式转为c。 |
①一般适用于不能隐式转换的类型之间的转换(双向均不能) ②reinterpret_cast直接从二进制位进行复制,是一种极其不安全的转换。 |
dynamic_cast |
①用于有继承关系的类指针间。 ②用于有交叉关系的类指针之间(即继承图上通过继承路径的可达的两个类之间,如,多继承的两个基类之间等。)
|
详见后面章节的分析 |
①dynamic_cast具有类型检查的功能,目标类型必须是类的指针或引用。 ②运行时检查,用于多态的类型转换(上转,下转和交叉转换),只能转换指针和引用且需要虚函数的支持,才不会报错。而static_cast转换,即使基类没有虚函数,编译也不会报错,但这种转换不完全。 ③dynamic_cast支持交叉转换,而satic_cast不支持这种转换 |
【实例分析】新式类型转化初探
#include <stdio.h> 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); //pi不能隐式转为pc,须用reinterpret_cast! } void const_cast_demo() { //用常量初始化引用,要分配内存。故j为变量,因加const而成只读变量 const int& j = 1;//j为引用--》只读变量,说明j不能做为左值而己 int& k = const_cast<int&>(j); //转为普通引用,k就是j的别名 k = 5; printf("k = %d\n", k); //5 printf("j = %d\n", j); //5 const int x = 2; //x为常量 int& y = const_cast<int&>(x);//此时,会为x分配内存 //int z = const_cast<int>(x); //oops,目标类型只能是引用或指针 y = 3; printf("x = %d\n", x); //2 printf("y = %d\n", y); //3 printf("&x = %d\n", &x); printf("&y = %d\n", &y); //x与y的内存地址是相同的 } void reinterpret_cast_demo() { int i = 0; char c = 'c'; int* pi = &i; char* pc = &c; pc = reinterpret_cast<char*>(pi); //ok,指针间 pi = reinterpret_cast<int*>(pc); //ok,指针间 pi = reinterpret_cast<int*>(i); //ok,整数与指针间 //c = reinterpret_cast<char>(i); //oops,基本类型间转换,要用static_cast } void dynamic_cast_demo() { int i = 0; int* pi = &i; char* pc = dynamic_cast<char*>(pi);//oops,目标类型应为类的指针或引用 } int main() { static_cast_demo(); const_cast_demo(); reinterpret_cast_demo(); dynamic_cast_demo(); return 0; }
3. 小结
(1)C方式的强制类型转换
①过于粗暴;②潜在的问题不易被发现;③不易在代码中定位
(2)新式类型转换以C++关键字的方式出现
①编译器能够帮助检查潜在的问题
②非常方便的在代码中定位
③支持动态类型识别(dynamic_cast)