C++的强制类型转换
- 引言
- 一、类型转换简介
- 二、上行、下行转换的概述
- 三、static_cast 静态类型转换
- 四、dynamic_cast 静态类型转换(推荐使用)
- 五、const_cast 常量转换
- 六、reinterpret_cast 重新解释转换(最不安全)
- 总结
引言
💡 作者简介:专注于C/C++高性能程序设计和开发,理论与代码实践结合,让世界没有难学的技术。包括C/C++、Linux、MySQL、Redis、TCP/IP、协程、网络编程等。
👉
🎖️ CSDN实力新星,社区专家博主
👉
🔔 专栏介绍:从零到c++精通的学习之路。内容包括C++基础编程、中级编程、高级编程;掌握各个知识点。
👉
🔔 专栏地址:C++从零开始到精通
👉
🔔 博客主页:https://blog.csdn.net/Long_xu
🔔 上一篇:【035】C++泛型编程(模板)实践:设计数组类模板模仿vector容器
一、类型转换简介
标准C++提供了一个显式的转换语法,用来代替C语言风格的类型转换。使用C语言风格的强制转换可以把想要的任何东西转换成我们需要的类型。
新类型的强制转换可以提供更好的控制强制转换过程,允许控制各种不同类型的强制转换。
C++风格的强制转换的好处:能更清晰的表明它们要干什么。开发者只要看一眼这样的代码,就能够立即知道一个强制转换目的。
C++中的类型转换允许将一个数据类型转换为另一个数据类型。C++提供了多种类型转换操作符和函数来执行不同类型之间的转换。
以下是C++中常见的类型转换方式:
-
隐式类型转换(Implicit Type Conversion):也称为自动类型转换,是编译器隐式地执行的类型转换。这种转换是安全的,可以由编译器自动完成,无需显式指定。例如,将一个整数赋值给一个浮点数变量,编译器会自动将整数转换为浮点数。
-
显式类型转换(Explicit Type Conversion):也称为强制类型转换,是通过使用转换操作符或函数来显式指定类型转换的方式。显式类型转换可能会导致数据丢失或精度损失。C++提供了以下三种显式类型转换方式:
- 静态转换(static_cast):用于基本数据类型之间的转换,以及具有继承关系的指针和引用之间的转换。
- 动态转换(dynamic_cast):用于具有继承关系的类之间的转换,可以在运行时检查类型转换的有效性。
- 常量转换(const_cast):用于去除指针或引用的常量属性。
-
重新解释转换(reinterpret_cast):用于将一个指针或引用转换为另一个不相关类型的指针或引用,这是一种非常危险的转换,需要谨慎使用。
类型转换应该在必要时使用,并且要确保转换的安全性。错误的类型转换可能导致数据丢失、不可预料的行为或程序崩溃。所以,在进行类型转换时,一定要了解数据类型的特点,并谨慎选择适当的转换方式。
二、上行、下行转换的概述
在C++中,上行转换(upcasting)和下行转换(downcasting)是指在继承关系中的类型转换。
-
上行转换(Upcasting):将派生类指针或引用转换为基类指针或引用。上行转换是安全的,因为派生类对象中包含了基类对象的所有成员。上行转换是隐式的,不需要显式指定,编译器会自动完成。例如,如果有一个基类Animal和一个派生类Dog,那么可以将Dog对象的指针或引用赋值给Animal对象的指针或引用。
-
下行转换(Downcasting):将基类指针或引用转换为派生类指针或引用。下行转换是不安全的,因为基类对象中可能没有派生类特有的成员。下行转换必须显式指定,并且需要使用
dynamic_cast
运算符进行类型检查。在运行时,dynamic_cast
会检查转换是否有效,如果转换无效,返回空指针(对于指针)或引发std::bad_cast
异常(对于引用)。例如,如果有一个基类Animal的指针或引用,可以使用dynamic_cast
将其转换为派生类Dog的指针或引用。
下行转换只有在确保基类对象指向的是派生类对象时才能安全进行。否则,进行下行转换可能会导致未定义的行为或程序崩溃。因此,在进行下行转换时,最好先使用dynamic_cast
进行类型检查,以确保转换的有效性。
三、static_cast 静态类型转换
static_cast 用于类层次结构中基类(父类)和派生类(子类)之间指针和引用的转换。它支持:
- 基本类型。
- 上行转换。
- 下行转换。
不支持不相干类型转换。
假设存在这样的类:
class Base{
};
class Son:public Base{
};
class Other{
};
(1)支持基本类型。
int num=static_cast<int>(3.1415);// ok
(2)支持上行转换,安全。
Base *p=static_cast<Base *>(new Son);// ok
(3)支持下行转换,不安全。
Son *p=static_cast<Son *>(new Base);// ok
(4)不支持不相关类型的转换。
Base *p=static_cast<Base *>(new Other);// error
完整示例:
#include <iostream>
using namespace std;
class Base {
};
class Son :public Base {
};
class Other {
};
int main()
{
int num = static_cast<int>(3.1415);// ok
Base *p = static_cast<Base *>(new Son);// ok
Son *p2 = static_cast<Son *>(new Base);// ok
//Base *p = static_cast<Base *>(new Other);// error
return 0;
}
四、dynamic_cast 静态类型转换(推荐使用)
dynamic_cast 主要用于类层次间的上行转换和下行转换。一种最安全的类型转换。
假设存在这样的类:
class Base{
};
class Son:public Base{
};
class Other{
};
(1)不支持基本类型。
int num=dynamic_cast<int>(3.1415);// error
(2)支持上行转换,安全。
Base *p=dynamic_cast<Base *>(new Son);// ok
(3)不支持下行转换,不安全。
Son *p=dynamic_cast<Son *>(new Base);// error
(4)不支持不相关类型的转换。
Base *p=dynamic_cast<Base *>(new Other);// error
完整示例:
#include <iostream>
using namespace std;
class Base {
};
class Son :public Base {
};
class Other {
};
int main()
{
int num = dynamic_cast<int>(3.1415);// error
Base *p = dynamic_cast<Base *>(new Son);// ok
Son *p2 = dynamic_cast<Son *>(new Base);// error
Base *p3 = dynamic_cast<Base *>(new Other);// error
return 0;
}
报错效果:
五、const_cast 常量转换
语法:
const_cast< new-type expression>(...)
返回new-type类型的值。
用途:
- 将const修饰的指针或引用转换成非const。
- 将非const修饰的指针或引用转换成const。
const int *p;
int *p2=const_cast<int *>(p);
const int &ob=10;
int &ob2=const_cast<int &>(ob);
int *p3;
const int *p4=const_cast<int *>(p3);
int ob3=10;
const int &ob4=const_cast<int &>(ob3);
const_cast只能进行以下转换。特别是,只有const_cast可用于抛弃(去除)恒常性或波动性。
(1)指向同一类型的两个可能的多级指针可以相互转换,而不必考虑每个级别上的cv限定符。
(2)任何类型的左值都可以转换为相同类型的左值或右值引用,或多或少受cv限制。同样,类类型的右值或任何类型的右值都可以转换为或多或少限定cv的右值引用。如果表达式是一个全局值,则引用const_cast的结果指向原始对象,否则指向物化的临时对象。
(4)同样的规则也适用于可能指向数据成员的多级指针,以及可能指向具有已知和未知边界的数组的多级指针(指向限定cv的元素的数组本身也被认为是限定cv的)。
(5)空指针值可以转换为new-type的空指针值。
示例:
#include <iostream>
struct type
{
int i;
type(): i(3) {}
void f(int v) const
{
// this->i = v; // compile error: this is a pointer to const
const_cast<type*>(this)->i = v; // OK as long as the type object isn't const
}
};
int main()
{
int i = 3; // i is not declared const
const int& rci = i;
const_cast<int&>(rci) = 4; // OK: modifies i
std::cout << "i = " << i << '\n';
type t; // if this was const type t, then t.f(4) would be undefined behavior
t.f(4);
std::cout << "type::i = " << t.i << '\n';
const int j = 3; // j is declared const
[[maybe_unused]]
int* pj = const_cast<int*>(&j);
// *pj = 4; // undefined behavior
[[maybe_unused]]
void (type::* pmf)(int) const = &type::f; // pointer to member function
// const_cast<void(type::*)(int)>(pmf); // compile error: const_cast does
// not work on function pointers
}
六、reinterpret_cast 重新解释转换(最不安全)
不支持基本类型,但是支持基本类型指针,而且其他的基本都支持,所以是最不安全的。
假设存在这样的类:
class Base{
};
class Son:public Base{
};
class Other{
};
(1)不支持基本类型,但支持基本类型指针。
int num=reinterpret_cast<int>(3.1415);// error
float *q;
int *p=reinterpret_cast<int *>(q);// ok
(2)支持上行转换。
Base *p=reinterpret_cast<Base *>(new Son);// ok
(3)支持下行转换。
Son *p=reinterpret_cast<Son *>(new Base);// ok
(4)支持不相关类型的转换。
Base *p=reinterpret_cast<Base *>(new Other);// ok
完整示例:
#include <iostream>
using namespace std;
class Base {
};
class Son :public Base {
};
class Other {
};
int main()
{
int num = reinterpret_cast<int>(3.1415);// error
float q = 3.16f;
float *q2 = &q;
int *num2 = reinterpret_cast<int *>(q2);// ok
Base *p = reinterpret_cast<Base *>(new Son);// ok
Son *p2 = reinterpret_cast<Son *>(new Base);// ok
Base *p3 = reinterpret_cast<Base *>(new Other);// ok
return 0;
}
总结
- 静态类型转换
静态类型转换是最常用的类型转换方式,它可以将一种类型的数据强制转换为另一种类型,但需要注意的是,这种转换可能会损失一些信息,因此在进行此类转换时应当谨慎。
例如:
int a = 10;
double b = static_cast<double>(a);
- 动态类型转换
动态类型转换主要用于多态类型之间的转换,它可以将基类指针或引用转换为派生类指针或引用。如果进行非法的类型转换,动态类型转换会返回一个空指针。
例如:
class Base {};
class Derived : public Base {};
Base* base = new Derived;
Derived* derived = dynamic_cast<Derived*>(base);
- 重新解释类型转换
重新解释类型转换可以将一个对象的二进制表示重新解释为另一种类型的对象,这种转换通常用于底层编程和特殊的系统级程序中。
例如:
int a = 100;
float b = reinterpret_cast<float&>(a);
- const_cast转换
const_cast转换可以将const限定符添加或移除,以便在需要更改底层值时使用,但要注意的是,const_cast转换可能会导致未定义行为。
例如:
const int a = 100;
int& b = const_cast<int&>(a);