static_cast
static_cast
是最常用的类型转换形式,用于各种明确的类型转换,如基本数据类型的转换(例如从 float
到 int
),或类层次结构中基类与派生类之间的转换(仅当存在明确的继承关系时)。
- 用途:
- 转换数值类型,例如整数和浮点数之间。
- 将派生类指针或引用转换为基类指针或引用,反之亦然(只要没有虚继承且路径明确)。
- 调用有显式类型转换的构造函数或转换操作符。
- 特性:
- 无运行时类型检查:
static_cast
在编译时进行类型检查,不提供运行时类型安全保障。这意味着,如果进行不适当的转换(如向下转换到一个实际不是该类型的对象),编译器可能不会报错,但程序运行时可能会导致错误或未定义行为。 - 上行转换是安全的:将派生类的指针或引用转换为基类的指针或引用通常是安全的,因为派生类对象总是包含基类部分。
- 下行转换是不安全的:将基类的指针或引用转换为派生类的指针或引用在没有运行时类型检查的情况下是不安全的,因为基类对象可能实际上不是派生类对象。
- 无运行时类型检查:
- 使用场景:
- 基本数据类型转换:
static_cast
可以用于基本数据类型之间的转换,例如将int
转换为char
,或者double
转换为int
。这种转换会根据需要进行适当的数值截断或转换。int i = 10; char c = static_cast<char>(i);
- 将任何类型的表达式转换成
void
类型:这允许将任何表达式转换为void
类型,通常用于忽略表达式的值,如在宏定义中使用。int x = 10; static_cast<void>(x); // 用于显式忽略x的值
- 类层次结构中的转换:
- 上行转换(安全):将派生类转换为基类。
- 下行转换(不安全):将基类转换为派生类,不推荐使用,除非确保转换是安全的。
class Base {}; class Derived : public Base {}; Derived d; Base* bp = &d; // 隐式转换,也可以显式用static_cast Derived* dp = static_cast<Derived*>(bp); // 风险操作,仅当确定bp确实指向Derived时使用
- 基本数据类型转换:
- 注意事项
- 尽管
static_cast
在编译时提供了一定程度的类型检查,但它不能保证转换的运行时安全性,尤其是在涉及复杂类层次结构的转换时。在使用static_cast
进行下行转换时,开发者需要确保转换的安全性,否则可能会引发运行时错误。在需要运行时检查的情况下,应该使用dynamic_cast
。
- 尽管
- 示例
double d = 9.23; int i = static_cast<int>(d); // 基本类型转换 class Base {}; class Derived : public Base {}; Derived* dp = new Derived(); Base* bp = static_cast<Base*>(dp); // 向上转换
dynamic_cast
dynamic_cast
主要用于类层次结构中,安全地将基类指针或引用转换为派生类指针或引用,并在运行时检查转换的有效性(使用RTTI,即运行时类型信息)。它只能用于包含虚函数的类。
- 用途:
- 安全地将基类指针或引用转为派生类指针或引用,当转换无效时,指针转换返回
nullptr
,引用转换抛出std::bad_cast
异常。
- 安全地将基类指针或引用转为派生类指针或引用,当转换无效时,指针转换返回
- 特性:
- 类型安全的下行转换:
dynamic_cast
用于类层次结构中的下行转换(将基类指针或引用转换为派生类指针或引用)时,它提供运行时类型检查,确保转换的目标类型是正确的。这种检查是基于对象的实际类型,不仅仅是它被声明的类型。 - 基于虚函数的运行时类型信息 (RTTI):为了使
dynamic_cast
能够执行这些运行时检查,基类需要至少有一个虚函数。这是因为虚函数的存在使得编译器为该类生成RTTI,dynamic_cast
使用这些信息来检查和确认转换的有效性。 - 转换目标:
- 可以转换为类的指针、引用或者
void*
。对于类的指针和引用,dynamic_cast
主要用于安全地进行下行转换。 - 转换为
void*
主要用于获取指向对象的最底层基类部分的指针。
- 可以转换为类的指针、引用或者
- 转换结果:
- 对于指针:如果转换失败(即如果尝试转换的类型与实际对象的类型不兼容),
dynamic_cast
返回nullptr
。 - 对于引用:如果转换失败,会抛出
std::bad_cast
异常。
- 对于指针:如果转换失败(即如果尝试转换的类型与实际对象的类型不兼容),
- 类型安全的下行转换:
- 示例
- 假设有一个类层次结构,其中
Base
类有一个虚函数,Derived
是Base
的一个派生类:#include <iostream> #include <typeinfo> // For std::bad_cast class Base { public: virtual void print() { std::cout << "Base class" << std::endl; } virtual ~Base() {} }; class Derived : public Base { public: void print() override { std::cout << "Derived class" << std::endl; } }; int main() { Base* b = new Derived(); // 向上转换,安全 try { Derived* d = dynamic_cast<Derived*>(b); // 向下转换,安全 if (d) { d->print(); // 成功调用 } else { std::cout << "Conversion failed." << std::endl; } Base* b2 = new Base(); // 基类对象 Derived* d2 = dynamic_cast<Derived*>(b2); // 转换失败,返回nullptr if (d2) { d2->print(); } else { std::cout << "Conversion failed." << std::endl; } Base& b3 = *b2; Derived& d3 = dynamic_cast<Derived&>(b3); // 引用转换失败,抛出异常 d3.print(); } catch (const std::bad_cast& e) { std::cout << "Bad cast: " << e.what() << std::endl; } delete b; delete b2; return 0; }
- 假设有一个类层次结构,其中
- 注意事项
dynamic_cast
在运行时检查的能力使其在需要确保类型安全的场景中非常有用,但这也意味着与其他更简单的转换(如static_cast
)相比,它的性能成本较高。- 在设计时应当注意,过度依赖
dynamic_cast
可能暗示设计上存在问题,可能需要重新考虑类的设计和接口。 dynamic_cast
不能用于基本数据类型的转换。dynamic_cast
主要用于对象的指针和引用之间的转换,特别是在涉及类层次结构中的对象时。它需要运行时类型信息(RTTI)来检查转换是否安全,这种信息仅在类类型的对象中可用,因为它们涉及到虚函数。- 对于基本数据类型,如
int
、float
、char
等,你应该使用static_cast
来进行转换。static_cast
提供了足够的功能来处理基本类型之间的转换,并且效率更高,因为它不涉及运行时类型检查。例如,如果你需要将double
转换为int
,你应该使用static_cast
,如下所示:double d = 9.57; int i = static_cast<int>(d); // 将 double 转换为 int
- 示例:
class Base { virtual void dummy() {} }; class Derived : public Base { int a; }; Base* bp = new Derived(); Derived* dp = dynamic_cast<Derived*>(bp); // 安全向下转换 if (dp) { // 转换成功 }
reinterpret_cast
reinterpret_cast
提供了低层次的强制类型转换,它可以将任何指针类型转换为任何其他指针类型,甚至可以将指针转换为足够大的整数类型。此转换的安全性和便携性不保证,应谨慎使用。
- 用途:
- 用于位的简单重新解释,如指针与整数之间的转换。
- 可以将整型转换为指针,也可以把指针转换为数组;可以在指针和引⽤⾥进⾏肆⽆忌惮的转换,平台移植性⽐价差。
- 将一个指针转换为不相关类型的指针。
- 示例:
long p = 0x12345678; char* cp = reinterpret_cast<char*>(&p); // 将long指针转换为char指针
const_cast
const_cast
用于修改类型的 const
或 volatile
属性。它是唯一能够去除对象的 const
(或添加)的C++类型转换操作符。
- 用途:
- 用于添加或去除对象的
const
或volatile
属性。
- 用于添加或去除对象的
- 示例:
const int ci = 10; int* modifiable = const_cast<int*>(&ci); *modifiable = 20; // 未定义行为,如果原始对象是常量