C++四种类型转换详解 | static_cast、dynamic_cast、const_cast、reinterpret_cast

C++为什么要引入四种类型转换? #

众所周知,C++ 关于类型转换引入了四种方式:static_castconst_castdynamic_castreinterpret_cast

为什么要引入这几种类型转换? #

C++ 完全兼容 C 语言,而 C 语言的类型转换非常灵活,可以在任意类型之间转换。然而,这种灵活性也带来了安全隐患。例如,可能将指向常量对象的指针转换为非常量对象的指针,或者将基类对象指针错误地转换为派生类对象指针。这些转换容易引入难以排查的bug,且需要仔细的代码审查才能发现。

C++ 引入这几种类型转换,可以在不同场景下使用不同的转换方式,从而提高代码的安全性和可维护性,同时也有利于代码审查。

四种类型转换的使用场景 #

static_cast #

使用方式

#include <iostream>
using namespace std;

struct Base {
    virtual void Func() { cout << "Base Func \n"; }
};

struct Derive : public Base {
    void Func() override { cout << "Derive Func \n"; }
};

int main() {
    float f = 1.23;
    cout << "f " << f << endl;
    int i = static_cast<int>(f);
    cout << "i " << i << endl;

    Derive d;
    d.Func();
    Base *b = static_cast<Base*>(&d);
    b->Func();

    return 0;
}

使用场景

  • 基本数据类型之间的转换,例如 floatintintchar 等。
  • 在有类型指针和 void* 之间转换。
  • 子类对象指针转换成父类对象指针。

static_cast 适用于非多态类型的转换,建议将所有的隐式类型转换用 static_cast 显示替换。不能用于不兼容的指针类型转换,例如将 float* 转换为 int*

dynamic_cast #

使用方式

#include <iostream>
using namespace std;

struct Base {
    virtual void Func() { cout << "Base Func \n"; }
};

struct Derive : public Base {
    void Func() override { cout << "Derive Func \n"; }
};

int main() {
    Derive d;
    d.Func();

    Base *b = dynamic_cast<Base*>(&d);
    b->Func();

    Derive *dd = dynamic_cast<Derive*>(b);
    dd->Func();

    return 0;
}

使用场景

  • 将父类的指针或引用转换为子类的指针或引用。
  • 父类必须要有虚函数,因为 dynamic_cast 在运行时检查,需要运行时类型信息(RTTI),而 RTTI 存储在虚函数表中。

const_cast #

使用方式

int main() {
    int data = 10;
    const int *cpi = &data;

    int *pi = const_cast<int*>(cpi);
    const int *cpii = const_cast<const int*>(pi);

    return 0;
}

使用场景

  • 常量指针或引用与非常量指针或引用之间的转换。
  • const_cast 是唯一可以对常量进行操作的类型转换,通常用于去除常量性。去除常量性是危险操作,需谨慎使用。

reinterpret_cast #

使用方式

int main() {
    int data = 10;
    int *pi = &data;

    float *fpi = reinterpret_cast<float*>(pi);

    return 0;
}

使用场景

  • 类似 C 语言中的强制类型转换,可以转换任意类型。
  • 万不得已时才使用,因为这种转换方式不安全,容易引入 bug。

总结 #

C++ 引入 static_castconst_castdynamic_castreinterpret_cast,是为了在不同场景下提供更安全、更明确的类型转换方式,同时便于代码审查和维护。虽然 reinterpret_cast 类似于 C 语言的强制类型转换,但由于其不安全性,应尽量避免使用。