- C语言中的类型转换
- 隐式类型转换
- 显示类型转换(强制类型转换)
- C++强制类型转化
- static_cast
- reinterpret_cast
- const_cast
- dynamic_cast
- explicit
C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与接收返回值类型不一致时,就需要发生类型转化
C语言中总共有两种形式的类型转换:隐式类型转换和显式类型转换。
隐式类型转换编译器在编译阶段自动进行,能转就转,不能转就编译失败
适用于相近的类型
void show(int i){
//参数的接收发生了隐式类型转换
std::cout << i << std::endl;
}
int main(){
double d = 1.1;
show(d);
return 0;
}
显示类型转换(强制类型转换)
需要用户自己处理,通常用于不相近类型的转换
int main(){
int a = 0;
int* p = &a;
//将指针强制转化为int类型
int b = (int)p;
}
C++强制类型转化
C语言的类型转化有很大的缺陷:
- 隐式类型转换可能会因为整形提升或者数据截断导致精度的丢失
- 隐式类型有时会被程序员忘记或者忽略,造成错误
- 显式类型转换将所有情况混合在一起,代码不够清晰,如果出现错误不好查
C++为了加强类型转化的规范性和可视性,引入了四种命名的强制类型转换操作符:static_cast、reinterpret_cast、const_cast、dynamic_cast
static_cast
static_cast用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用static_cast,但它不能用于两个不相关的类型进行转换。(即对应C语言中的隐式类型转换)
int main(){
double d = 1.1;
//可以让隐式类型转化更加规范
int a = static_cast(d);
std::cout << i;
}
reinterpret_cast
reinterpret_cast是一种较为危险的类型转换,通常为操作数的位模式提供较低层次的重新解释,用于将一种类型转换为另一种不同的类型,通常适用于指针、引用、以及整数之间的类型转换。对应C语言的强制类型转化
int main(){
int a = 998;
int* p1 = &a;
//这里的强制类型转化,是把int指向的空间强制转化成了double指向的空间
//所以p1以前读取四个字节内容,转换后p2可以读取八个字节内存,所以p1在转换后指向的内容发生了变化
double* p2 = reinterpret_cast(p1);
std::cout << *p2 <
const_cast
通常用于删除变量的const属性
int main(){
//const变量会被编译器优化放到寄存器,加上volatile防止编译器优化
volatile const int a = 2;
int* p = const_cast(&a);
*p = 3;
std::cout << a << std::endl;
std::cout << *p << std::endl;
return 0;
}
dynamic_cast
将基类的指针或引用安全地转换成派生类的指针或引用
基类和派生类之间的转换分为两种
- 向上转型:子类对象指针/引用->父类指针/引用(切片,原生支持的)
- 向下转型:父类对象指针/引用->子类指针/引用(用dynamic_cast转型是安全的)
dynamic_cast的向下转换``只支持继承中的多态类型,也就是父类之中必须包含虚函数
class A {
public:
virtual void f() = 0;
};
class B : public A{
public:
virtual void f() {
cout << "f()::B" << endl;
}
void showB() {
cout << "showB()::B" << endl;
}
};
int main() {
A* pa = new B;
//把基类指针强制转换为派生类指针
B* pb = dynamic_cast(pa);
//转换时会做安全检查,如果不能成功转换就会返回0
if (pb) {
pb->showB();
}
return 0;
}
- dynamic_cast只能用于含有虚函数的类
- dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0
explicit
在C++中,explicit关键字用来修饰类的构造函数,被修饰的构造函数的类,不能发生相应的隐式类型转换,只能以显示的方式进行类型转换
class A{
public:
explicit A(int a){
cout << "A(int a)" << endl;
}
private:
int _a;
};
int main(){
A a1(1);
// 隐式转换-> A tmp(1); A a2(tmp);
A a2 = 1;
}
a2使用赋值进行初始化,其实是先把1隐式类型转换为一个临时对象,然后用临时对象对a2进行赋值
使用explicit关键字修饰构造函数,A就不会进行隐式类型转换



