第2章:类型转换(Type Conversions)
一、导读
1.1 本章学习目标
第2章讲解 C++ 的四种类型转换操作符:static_cast、dynamic_cast、const_cast、reinterpret_cast。Meyers 强调应该用这些操作符替代 C 风格的强制转换。
本章核心学习目标:
- 掌握四种类型转换的用途和限制
- 理解为什么应该避免 C 风格转换
- 掌握 dynamic_cast 的安全向下转型
1.2 为什么本章如此重要
类型转换是 C++ 中最容易出错的区域之一。C 风格的转换可以绕过类型系统,导致难以发现的错误。C++ 的四种转换操作符提供了更安全、更明确的替代方案。
1.3 核心问题引导
static_cast 和 dynamic_cast 有什么区别?
什么时候应该使用 const_cast?
为什么 reinterpret_cast 如此危险?
二、核心概念详解
2.1 四种类型转换
cpp
// 1. static_cast: 编译时类型转换
int i = 42;
double d = static_cast<double>(i); // int → double
Base* base = new Derived;
Derived* derived = static_cast<Derived*>(base); // 向下转型(不安全!)
// static_cast 不检查运行时类型,如果 base 实际不是 Derived,行为未定义
// 2. dynamic_cast: 运行时安全的向下转型
Base* base = new Derived;
if (Derived* derived = dynamic_cast<Derived*>(base)) {
// 转换成功,base 确实是 Derived
derived->derivedMethod();
} else {
// 转换失败,base 不是 Derived
}
// 要求: 基类必须有虚函数
// 代价: 运行时开销(RTTI)
// 3. const_cast: 移除 const/volatile
const int* cp = &i;
int* p = const_cast<int*>(cp); // 移除 const
// 通过 p 修改 i 是未定义行为(如果 i 本身是 const)
// 4. reinterpret_cast: 低级别的位模式转换
int* ptr = new int(42);
intptr_t addr = reinterpret_cast<intptr_t>(ptr); // 指针 → 整数
void (*func)() = reinterpret_cast<void(*)()>(0x1234); // 整数 → 函数指针
// 极度危险!几乎总是错误的2.2 替代 C 风格转换
cpp
// C 风格转换: (type)expression
// 等价于依次尝试:
// 1. const_cast
// 2. static_cast
// 3. static_cast + const_cast
// 4. reinterpret_cast
int i = 42;
double d = (double)i; // C 风格
double d2 = static_cast<double>(i); // C++ 风格(明确意图)
// C++ 风格的优势:
// 1. 容易识别和搜索(grep 友好)
// 2. 明确表达转换意图
// 3. 编译器可以做更多检查
// 避免 C 风格转换:
class Base { virtual ~Base() = default; };
class Derived : public Base { };
Base* b = new Derived;
// Derived* d = (Derived*)b; // C 风格: 可能是 static_cast 或 reinterpret_cast
Derived* d = static_cast<Derived*>(b); // 明确: 我知道这是向下转型
Derived* d2 = dynamic_cast<Derived*>(b); // 更安全: 运行时检查三、实战案例
3.1 案例一:dynamic_cast 的安全使用
cpp
class Shape {
public:
virtual ~Shape() = default;
virtual void draw() = 0;
};
class Circle : public Shape {
public:
void draw() override { /* 画圆 */ }
double radius() const { return 5.0; }
};
class Rectangle : public Shape {
public:
void draw() override { /* 画矩形 */ }
double width() const { return 10.0; }
};
void processShape(Shape* shape) {
// 安全地向下转型
if (auto* circle = dynamic_cast<Circle*>(shape)) {
std::cout << "Circle with radius " << circle->radius() << "\n";
} else if (auto* rect = dynamic_cast<Rectangle*>(shape)) {
std::cout << "Rectangle with width " << rect->width() << "\n";
}
// 或者使用 visitor 模式避免 dynamic_cast
}四、本章小结
static_cast 用于编译时安全的类型转换
dynamic_cast 用于运行时安全的向下转型(需要虚函数)
const_cast 仅用于移除 const,谨慎使用
reinterpret_cast 极度危险,几乎总是错误的
五、思考与练习
思考题
dynamic_cast 的运行时开销有多大?
什么时候应该用 visitor 模式替代 dynamic_cast?
编程练习
实现一个类型安全的 Any 类,内部使用 dynamic_cast 或 type_info。
重写一段使用 C 风格转换的代码,改为使用 C++ 转换操作符。