# dynamic_cast 与 typeid

URL: https://caijiao.org/cpp/oop/rtti
Source: docs/cpp/oop/rtti.md
Description: 本节讲解 'dynamic_cast' 和 'typeid' 操作符，分析它们在运行时类型识别中的作用及使用方法。

在 C++ 中，`dynamic_cast` 和 `typeid` 是两个用于运行时类型识别（RTTI）的重要工具。它们使得程序能够在运行时确定对象的实际类型，并在需要时进行安全的类型转换。理解这两者的工作原理是深入掌握 C++ 类型系统的关键。

## `dynamic_cast`：安全的类型转换

`dynamic_cast` 是 C++ 中用于安全地进行指针或引用类型转换的操作符。它主要用于多态类型的转换，可以在类层次结构中进行上下游的转换。`dynamic_cast` 在运行时检查类型转换是否合法，避免了在不安全转换时引发的错误。

### 使用 `dynamic_cast`

`dynamic_cast` 主要用于将基类指针或引用转换为派生类指针或引用。如果转换不合法（即指针指向的对象并不是目标类型的对象），`dynamic_cast` 会返回 `nullptr`（对于指针）或者抛出 `std::bad_cast` 异常（对于引用）。

### 示例：使用 `dynamic_cast` 进行类型转换

```cpp
#include <iostream>
using namespace std;

class Base {
public:
    virtual void show() { cout << "Base class" << endl; }
    virtual ~Base() {}  // 虚析构函数
};

class Derived : public Base {
public:
    void show() override { cout << "Derived class" << endl; }
};

int main() {
    Base* base = new Derived();

    // 使用 dynamic_cast 进行类型转换
    Derived* derived = dynamic_cast<Derived*>(base);
    if (derived) {
        derived->show();  // 输出 Derived class
    } else {
        cout << "Conversion failed!" << endl;
    }

    delete base;
    return 0;
}
````

### 输出：

```
Derived class
```

### 解释

* 在此例中，`Base` 类具有一个虚函数 `show()`，`Derived` 类重写了该函数。通过 `dynamic_cast`，程序能够安全地将基类指针 `base` 转换为派生类指针 `derived`。
* 如果 `base` 指向的对象并不是 `Derived` 类型，`dynamic_cast` 会返回 `nullptr`，表示转换失败。

## `typeid`：获取类型信息

`typeid` 是 C++ 提供的另一个运行时类型识别工具，它用于获取一个对象的类型信息，并返回一个 `std::type_info` 对象。`typeid` 可以应用于对象或类型的表达式。

### 使用 `typeid`

`typeid` 可用于获取对象的实际类型，而不是声明时的类型。它可以与多态一起使用，帮助判断运行时的对象类型。

### 示例：使用 `typeid`

```cpp
#include <iostream>
#include <typeinfo>
using namespace std;

class Base {
public:
    virtual void show() { cout << "Base class" << endl; }
    virtual ~Base() {}
};

class Derived : public Base {
public:
    void show() override { cout << "Derived class" << endl; }
};

int main() {
    Base* base = new Derived();

    // 使用 typeid 获取类型信息
    cout << "Type of base: " << typeid(*base).name() << endl;  // 输出 Derived 的类型信息

    delete base;
    return 0;
}
```

### 输出：

```
Type of base: Derived
```

### 解释

* `typeid(*base)` 返回 `base` 指针所指向对象的实际类型信息，在此例中为 `Derived`。
* `typeid` 可以与多态对象一起使用，帮助确定运行时的类型，而不是静态类型。

## `dynamic_cast` 与 `typeid` 的关系

* `dynamic_cast` 和 `typeid` 都依赖于 C++ 的运行时类型识别（RTTI）机制。`dynamic_cast` 进行安全的类型转换，而 `typeid` 则用于获取对象的实际类型信息。
* `dynamic_cast` 适用于类型转换，尤其是涉及多态类型时，而 `typeid` 适用于获取类型信息，并且通常用于类型比较或输出。

## 小结

* **`dynamic_cast`**：用于安全地进行类型转换，主要在有继承关系的类中使用，特别是涉及到多态时。通过 `dynamic_cast`，可以避免非法转换和潜在的错误。
* **`typeid`**：用于获取对象的实际类型信息，常与多态一起使用。通过 `typeid`，可以在运行时判断对象的真实类型。

理解和使用 `dynamic_cast` 和 `typeid` 能够帮助开发者更好地进行类型管理和调试，尤其是在面向对象编程中。
