C++的类型转换,有隐式类型转换,也有显式类型转换。
1. 隐式类型转换
隐式类型转换不需要程序员接入,直接就能转换。
几种常见的隐式类型转换:
- 算数转换,char、int、float、double、long等算数类型间的转换
- 无符号算数类型转换,unsigned int、float等之间的转换
- 数组转换成指针
- 指针的转换
- bool值的转换,在代码中基本任意类型都可以在if中作为判断条件,要注意类型转换
- 常指针和常量引用的转换,常引用转换要注意是否生成临时变量(引用右值)
- 类类型定义的转换,通常是构造函数实现的隐式构造(非explicit)
2. 显式类型转换
显式类型转换需要在代码中写明转换方式。
C++中有多种类型转换方式:
- 强制类型转换,与C语言类似
- static_cast
- dynamic_cast
- reinterpret_cast
- const_cast
2.1. C语言 强制类型转换
想怎么转就怎么转,随便转,随心所欲的转:
class A{}
class B{}
int main()
{
A a;
B *b = (B *)&a; // 这也可以转
int a1 = 100;
void *p1 = (void *)&a1;
char *p2 = (char *)&a1;
char *c_str = "hello world";
int a2 = (int)c_str;
}
强制类型转换其实就是对内存的不同解析方式。
这种转换方式高效便捷,但是没有编译时的类型检查,有可能在调用时出错。
2.2. static_cast
带安全检查的类型转换
同样是上面的代码,下面这句就编译不过:
B *p = static_cast<B *>(&a); // A和B之间没有继承关系,不能类型转换
static_cast用于替代强制类型转换,此转换会在编译时进行类型检查,而强制转换不会。
2.3. dynamic_cast
dynamic_cast用于类层次间的上行转换和下行转换(基类必须有虚表),除了在编译器进行类型安全检查,dynamic_cast还会在运行时类型检查。
从子类转为父类型时,dynamic_cast和static_cast是一致的;而从父类转为子类的过程中,static_cast是非类型安全的,而dynamic_cast会在转换时做类型安全检查,若不能转换则返回NULL或抛出异常(在引用类型转换失败时抛出异常)。
class A{}
class B : public A{}
int main()
{
A a;
B *b = static_cast<B *>(&a); // 编译不报错
B *b2 = dynamic_cast<B*>(&a); // 编译报错,因为A中没有虚函数
}
在有虚函数父子类之间互相转换请使用dynamic_cast。
2.4. reinterpret_cast
reinterpret_cast用于进行各种不同类型的指针之间、不同类型的引用之间以及指针和能容纳指针的整数类型之间的转换,转换不检查安全性。其实reinterpret_cast和普通强制类型转换没多大区别,也不是类型安全的,用reinterpret_cast的好处是:
- 将强制类型转换标准化,代码看着顺眼,而且能快速查找到强制类型转换
- 不改变参数const属性
2.5. const_cast
仅是将const类型的参数转换为非const型,不做其他转换操作;而其他三个类型转换操作符都不能改变参数的const属性。
const char* str ="hello world";