1.const_cast:用于添加或移除const、volatile限定符:
注意,const_cast只能去除用于修改那些原本不是常量,但被传递为常量的指针或引用。
#include <bits/stdc++.h>
const int global_num = 10;
int global_num2 = 11;
int main(){
const int local_num = 5;
int* global_ptr1 = const_cast<int*> (&global_num);
//*global_ptr1 ++; //段错误
int* local_ptr1 = const_cast<int*> (&global_num);
//*local_ptr1++; //可能可以通过编译,但不安全
int local_num2 = 6;
const int* ptr1 = &global_num2;
const int* ptr2 = &local_num2;
int* global_ptr2 = const_cast<int*>ptr1;
*global_ptr2 ++; //合法
cout<<"*global_ptr2 "<<*global_ptr2 <<endl;
int* local_ptr2 = const_cast<int*>ptr2;
cout<<"*local_ptr2 "<<*local_ptr2<<endl;
cout<<"global_num2 "<<global_num2<<endl;
cout<<"local_num2 "<<local_num2 <<endl;
return 0;
}
2.static_cast:用于相关类型之间的转换,是最常用的类型转换。
需注意:static_cast只能向上转换,即可以把派生类转换为基类,无法将基类转换为派生类。因为它在编译时进行类型检查,而无法在运行时验证对象的实际类型。
#include <iostream>
class Base {
public:
virtual void show() { std::cout << "Base\n"; }
virtual ~Base() = default; // 添加虚析构函数
};
class Derived : public Base {
public:
void show() override { std::cout << "Derived\n"; }
void special() { std::cout << "Special function\n"; }
int derived_data = 100; // 添加派生类特有数据
};
int main() {
// 1. 基本数据类型转换 - 安全
double d = 3.14;
int i = static_cast<int>(d);
std::cout << "数值转换: " << i << std::endl;
// 2. 指针向上转型(派生类→基类)- 安全
Derived derived;
Base* base_ptr = static_cast<Base*>(&derived);
base_ptr->show(); // 输出 "Derived"
// 3. 指针向下转型(基类→派生类)- 不安全!
Base base;
// 危险:Base对象没有Derived的完整内存布局
Derived* derived_ptr = static_cast<Derived*>(&base);
// derived_ptr->special(); // 未定义行为!
// derived_ptr->derived_data = 200; // 更危险:写入非法内存
// 4. 引用向上转型 - 安全
Derived& derived_ref = derived;
Base& base_ref = static_cast<Base&>(derived_ref); // 向上转型,安全
base_ref.show(); // 输出 "Derived"
// 5. 引用向下转型 - 不安全!
Base& base_ref2 = base;
// 危险:引用向下转型
Derived& derived_ref2 = static_cast<Derived&>(base_ref2); // 编译通过,但危险
// derived_ref2.special(); // 未定义行为!
// 6. 相对安全的向下转型(当你知道对象实际类型时)
Base* base_ptr2 = &derived; // 实际上指向Derived对象
Derived* derived_ptr2 = static_cast<Derived*>(base_ptr2); // 相对安全
derived_ptr2->special(); // 安全,因为base_ptr2确实指向Derived
return 0;
}
3.dynamic_cast:用于多态类型的安全向下转型,在运行时检查类型。
#include <iostream>
#include <typeinfo>
class Base {
public:
virtual ~Base() = default; // 必须有虚函数,因为虚函数表(vtable)包含了类型信息,没有虚函数的类没有 vtable,dynamic_cast 无法工作。
virtual void show() { std::cout << "Base\n"; }
};
class Derived : public Base {
public:
void show() override { std::cout << "Derived\n"; }
void special() { std::cout << "Special function\n"; }
};
class Unrelated {};
int main() {
// 1. 成功的向下转型,base1 虽然声明为 Base*,但实际指向的是 Derived 对象,dynamic_cast 在运行时检查对象的实际类型,发现实际类型是 Derived,与目标类型匹配,转换成功,返回有效的 Derived* 指针。
Base* base1 = new Derived();
Derived* derived1 = dynamic_cast<Derived*>(base1);
if (derived1) {
derived1->special(); // 可以调用
}
// 2. 失败的向下转型,dynamic_cast 发现实际类型是 Base,不是 Derived,目标类型 Derived 与实际类型 Base 不兼容,转换失败,返回 nullptr
Base* base2 = new Base();
Derived* derived2 = dynamic_cast<Derived*>(base2);
if (!derived2) {
std::cout << "Downcast failed!\n";
}
// 3. 引用转型(失败时抛出异常)
try {
Derived& derived_ref = dynamic_cast<Derived&>(*base1); // 成功
Base base_obj;
Derived& bad_ref = dynamic_cast<Derived&>(base_obj); // 抛出 std::bad_cast
} catch (const std::bad_cast& e) {
std::cout << "Bad cast: " << e.what() << std::endl;
}
delete base1;
delete base2;
return 0;
}
4.reinterpret_cast:用于不相关类型之间的低级重新解释,最危险的转换。
-
简单地进行二进制位的重新解释
-
不进行任何类型检查或转换
-
完全信任程序员知道自己在做什么
#include <iostream>
#include <cstdint>
int main() {
// 1. 指针类型之间的转换,int* 和 char* 是语义完全不同的类型,reinterpret_cast 无视这种语义差异,直接重新解释内存,编译器无法进行任何类型安全检查
int num = 0x12345678;
char* char_ptr = reinterpret_cast<char*>(&num);
std::cout << "Bytes: ";
for(int i = 0; i < sizeof(num); i++) {
std::cout << std::hex << static_cast<int>(char_ptr[i]) << " ";
}
std::cout << std::endl;
// 2. 指针和整数之间的转换,uintptr_t 的大小可能因平台而异,转换后的指针可能不满足类型对齐要求,整数值可能不是有效的内存地址
uintptr_t int_val = reinterpret_cast<uintptr_t>(&num);
int* num_ptr = reinterpret_cast<int*>(int_val);
// 极度危险的例子
int* dangerous_ptr = reinterpret_cast<int*>(0x12345678);
*dangerous_ptr = 42; // 可能访问受保护的内存,导致段错误
// 3. 不相关类指针转换
class A { public: int x; };
class B { public: int y; };
A a;
B* b_ptr = reinterpret_cast<B*>(&a); // 危险!容易破坏内存安全
b_ptr->y = 100; // 实际上修改了 a.x
// 4.适用场景1:序列化和反序列化
// 将对象转换为字节流进行存储或传输
struct Data {
int id;
double value;
};
void serialize(const Data& data, char* buffer) {
// 将Data对象的内存直接复制到缓冲区
memcpy(buffer, reinterpret_cast<const char*>(&data), sizeof(Data));
}
void deserialize(const char* buffer, Data& data) {
// 从缓冲区恢复Data对象
memcpy(reinterpret_cast<char*>(&data), buffer, sizeof(Data));
}
// 5.适用场景2:与C API交互
extern "C" {
void c_function(void* data);
}
void call_c_api(const MyData& data) {
// C API通常使用void*,需要转换
c_function(reinterpret_cast<void*>(const_cast<MyData*>(&data)));
}
return 0;
}
5.总结对比

C++四种强制类型转换详解
1148

被折叠的 条评论
为什么被折叠?



