C++ 中的四种类型转换运算符(static_cast
、dynamic_cast
、const_cast
、reinterpret_cast
)及其正确使用场景
1. static_cast(静态转换)
static_cast 是 C++ 提供的 编译时(静态)类型转换,主要用于已知安全的类型转换。它比 C 风格 (T)value 更加安全,具有更明确的语义,并在编译时进行类型检查.
1.1 正确用法:基本数据类型转换
#include <iostream>
int main() {
double d = 3.14;
int i = static_cast<int>(d); // 将 double 转换为 int
std::cout << "i = " << i << std::endl; // 输出:3
return 0;
}
1.2 正确用法:基类与派生类之间的向上转换
#include <iostream>
class Base {
public:
virtual ~Base() {} // 为 dynamic_cast 保证多态
};
class Derived : public Base {};
int main() {
Derived d;
// 向上转换:从 Derived* 转为 Base*
Base* b = static_cast<Base*>(&d);
std::cout << "Base pointer: " << b << std::endl;
return 0;
}
1.3 UB 案例:错误的向下转换
如果将一个 Base 对象错误地转换为 Derived 类型,将导致 UB。
#include <iostream>
class Base {};
class Derived : public Base {};
int main() {
Base b;
// 错误:Base 对象并不包含 Derived 的信息
Derived* d = static_cast<Derived*>(&b); // UB:不正确的向下转换
// 这里 d 指向的数据不包含 Derived 的特有部分,后续使用 d 可能导致崩溃或错误
return 0;
}
2. dynamic_cast(动态转换)
dynamic_cast 是 C++ 运行时类型转换(RTTI, Run-Time Type Information) 机制的一部分,主要用于基类和派生类之间的转换,尤其是 安全的向下转换(Base → Derived)。
2.1 正确用法:向下转换(需要多态类型)
#include <iostream>
class Base {
public:
virtual ~Base() {} // 必须有虚函数
};
class Derived : public Base {
public:
void hello() { std::cout << "Hello from Derived!" << std::endl; }
};
int main() {
Base* b = new Derived();
// 尝试将 Base* 动态转换为 Derived*
Derived* d = dynamic_cast<Derived*>(b);
if (d) {
d->hello(); // 转换成功,调用 Derived 的方法
} else {
std::cout << "Conversion failed." << std::endl;
}
delete b;
return 0;
}
2.2 UB 案例:对非多态类型使用 dynamic_cast
如果基类没有虚函数,则 dynamic_cast 无法执行正确的运行时检查,结果将是 UB。
#include <iostream>
class Base { /* 没有虚函数 */ };
class Derived : public Base {};
int main() {
Base* b = new Derived();
// 尝试进行动态转换,但 Base 不是多态类型
Derived* d = dynamic_cast<Derived*>(b); // UB:因为 Base 没有虚函数
if (d) {
std::cout << "Converted successfully." << std::endl;
} else {
std::cout << "Conversion failed." << std::endl;
}
delete b;
return 0;
}
3. const_cast(去除 const/volatile 限定符)
3.1 正确用法:修改可变数据
如果对象本身不是 const,通过 const_cast 去除指针的 const 属性。
#include <iostream>
void modify(const char* str) {
// 修改非 const 字符数组是安全的
char* p = const_cast<char*>(str);
p[0] = 'H';
}
int main() {
char str[] = "hello";
modify(str);
std::cout << "Modified string: " << str << std::endl; // 输出:Hello
return 0;
}
3.2 UB 案例:修改真正的 const 对象
如果对象本身是 const,再通过 const_cast 修改会导致 UB。
#include <iostream>
int main() {
const int a = 10;
// a 本身是 const,将其地址转换为 int* 后修改是未定义行为
int* p = const_cast<int*>(&a);
*p = 20; // UB:尝试修改只读数据
std::cout << "a = " << a << std::endl;
return 0;
}
4. reinterpret_cast(重解释转换)
4.1 正确用法:指针与整数之间转换
#include <iostream>
#include <cstdint>
int main() {
int a = 42;
// 将指针转换为整数
uintptr_t addr = reinterpret_cast<uintptr_t>(&a);
// 再转换回指针
int* p = reinterpret_cast<int*>(addr);
std::cout << "*p = " << *p << std::endl; // 输出:42
return 0;
}
4.2 UB 案例:错误地将不同类型的指针相互转换
如果将一个类型的指针错误地解释为另一个不兼容类型,会导致 UB。
#include <iostream>
int main() {
int a = 10;
// 错误地将 int* 转换为 double*
double* p = reinterpret_cast<double*>(&a);
// 尝试以 double* 方式访问内存,可能破坏内存布局,导致 UB
std::cout << "*p = " << *p << std::endl; // UB
return 0;
}
5. C 风格转换((T)value)
5.1 案例:C 风格转换的混合行为
C 风格转换可能同时应用了 static_cast、const_cast 和 reinterpret_cast,容易引入隐患,不推荐使用。
#include <iostream>
class Base {};
class Derived : public Base {};
int main() {
Base b;
// C 风格转换将 b 强制转换为 Derived*,相当于 static_cast 和 reinterpret_cast 的混合,
// 没有运行时检查,可能导致 UB
Derived* d = (Derived*)&b; // UB
return 0;
}
视频链接:
关注微信公众号 程序员陈子青 解锁你的高薪offer之旅。