1. C语言中的类型转换
在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与接收返回值类型不一致时,就需要发生类型转换,C语言中共有两种形式的类型转换:隐式类型转换和显式类型转换。
1.隐式类型转换:编译器在编译阶段自动进行,能转就转,不能转就编译失败
2.显时类型转换:需要用户自己处理
缺陷:转换的可视性较差,所有的转换类型都是用一种相同的形式书写,难以跟踪错误的转换。
2. 为什么C++需要四种类型转换
解决C风格类型转换的缺陷
C语言中的类型转换存在以下问题:
- 缺乏安全性检查:如父类指针强制转换为子类指针时,可能指向非子类对象,导致内存越界。
- 语义模糊:所有转换都用同一语法(如
(int*)
),难以区分不同场景(如常量性修改、类层次转换等),代码可读性差。 - 隐式风险:例如将
const
指针转为非const
指针,可能导致未定义行为,但编译器不会警告。
C++要兼容C语言,所以C++还可以使用C语言的转换风格。
3. C++强制类型转换
通过四种专用操作符,限制转换场景并引入安全检查:
static_cast
:用于安全的隐式转换(如基本类型转换、类层次上行转换),禁止无关类型转换(如int*
转double*
)。dynamic_cast
:在类层次下行转换时进行运行时类型检查(需父类有虚函数),失败返回nullptr
或抛出异常,避免非法访问。const_cast
:明确用于修改const
或volatile
属性,避免意外修改常量对象。reinterpret_cast
:低级别位模式转换(如指针转整数),明确标识高风险操作。
3.1 static_cast
基本类型转换
double d = 3.14;
int i = static_cast<int>(d); // 显式截断小数部分
编译器隐式执行的任何类型转换都可用static_cast,但它不能用于两个不相关的类型进行转换
以下类型被视为相关类型(Related Types),可安全使用static_cast
:
- 同一继承链的类(基类↔派生类)
- 基本数值类型互转(如
int
→double
,float
→long
) - 用户定义转换支持的类型(通过构造函数或
operator
重载) void*
与其他对象指针(需显式指明目标类型)
什么叫不相关的类型:
- 无继承关系:不在同一个类层次结构中(非基类与派生类)。
- 无标准转换规则支持:无法通过隐式转换或用户定义的转换函数建立联系。
- 内存布局不兼容:类型的大小、对齐方式或二进制表示差异较大。
class A {};
class B {};A* a = new A();
// B* b = static_cast<B*>(a); // 编译错误:A与B无继承关系 int x = 10;
int* p = &x;
// double* dp = static_cast<double*>(p); // 编译错误:int*与double*无关联 struct Vec3 { float x, y, z; };
// int n = static_cast<int>(Vec3{1,2,3}); // 编译错误:无用户定义的转换规则
3.2 reinterpret_cast
用于将一种类型转换成另一种不同的类型:
int* p = new int(42);
uintptr_t addr = reinterpret_cast<uintptr_t>(p); // 地址转整数
3.3 const_cast
最常用的用途就是删除变量的const属性,方便赋值
const int x = 10;
int* px = const_cast<int*>(&x); // 语法允许
*px = 20; // 未定义行为!x可能存储在只读内存
3.4 dynamic_cast
用于将一个父类对象的指针/引用转换为子类对象的指针或引用(动态转换)
dynamic_cast
是 C++ 中**唯一依赖运行时类型信息(RTTI)的类型转换操作符,专用于处理 类层次结构中的多态类型安全转换。其核心逻辑为:
- 运行时类型检查:通过查询对象的虚函数表(vtable)获取实际类型信息,验证目标类型是否与对象真实类型兼容。
- 安全失败机制:若转换不合法(如父类对象并非目标子类实例),指针转换返回
nullptr
,引用转换抛出std::bad_cast
异常。 - 多态性依赖:要求基类至少有一个虚函数(否则无法生成虚表,编译报错)。
class Animal {
public:virtual ~Animal() {} // 必须至少有一个虚函数
};
class Dog : public Animal {
public: void bark() { /* 子类特有方法 */ }
};Animal* animal = new Dog(); // 多态指针
Dog* dog = dynamic_cast<Dog*>(animal); // 合法:animal实际指向Dog对象
if (dog) dog->bark(); // 安全调用子类方法
class A { virtual ~A() {} };
class B : public A {};
class C : public A {};A* obj = new B();
C* c = dynamic_cast<C*>(obj); // 返回nullptr,因obj实际是B类型
A类对象obj并非C类实例,而是B类实例
转换类型 | 典型场景 | 安全检查 | 性能开销 | 使用频率 |
---|---|---|---|---|
static_cast | 类型关联明确的转换 | 编译期检查 | 无 | ⭐⭐⭐⭐ |
dynamic_cast | 多态类型下行转换 | 运行时检查 | 较高 | ⭐⭐ |
const_cast | 常量性/易变性修改 | 无 | 无 | ⭐ |
reinterpret_cast | 底层内存重解释 | 无 | 无 | ⭐ |