30、类型转换

厨子大约 3 分钟C++C++基础编程程序厨

首先提出一个问题,C语言中已经有类型转换,**C++****中为什么还要添加类型转换?**它和C语言的有什么区别?

为了更加安全

C++完全兼容C语言,C语言的转换方式很简单,可以在任意类型之间转换,但这也恰恰是缺点,因为极其不安全,可能不经意间将指向const对象的指针转换成非const对象的指针,可能将基类对象指针转成了派生类对象的指针,这种转换很容易出bug,需要严格审查代码才能消除这种隐患,可C这种转换方式不利于我们审查代码,且程序运行时也可能会出bug。

C++引入的几种类型转换可以完美的解决上述问题,不同场景下使用不同的类型转换方式,同时还有利于代码审查。

那C++引入了哪几种类型转换?

一共有四个:

  1. static_cast
  2. const_cast
  3. dynamic_cast
  4. reinterpret_cast

static_cast

使用场景:基本数据类型之间的转换使用,例如floatintintchar等,在有类型指针和void*之间转换使用,子类对象指针转换成父类对象指针也可以使用static_cast

非多态类型转换一般都使用static_cast,而且最好把所有的隐式类型转换都用static_cast进行显式替换,但不能使用static_cast在有类型指针之间进行类型转换。

示例代码:

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

dynamic_cast

使用场景:一般用于将父类的指针转换为子类的指针,此场景下父类必须要有虚函数,因为dynamic_cast是运行时检查,检查需要有运行时信息RTTI,而RTTI存储在虚函数表中,这块可以看看我这篇https://zhuanlan.zhihu.com/p/156880783。open in new window

如果父类没有虚函数,或者转换的双方不是父子关系,dynamic_cast会返回nullptr

示例代码:

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;
}

const_cast

使用场景:一般用于常量指针与非常量指针之间的转换,只有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;
}

reinterpret_cast

使用场景:类似C语言中的强制类型转换,基本上什么都可以转(static_castconst_cast转不了的就找reinterpret_cast),万不得已不要使用,因为不安全,有bug风险。

一般如果前三种转换方式不能解决问题,才考虑使用这种强制类型转换方式。

示例代码:

int main() {
    int data = 10;
    int *pi = &data;
    float *fpi = reinterpret_cast<float *>(pi);
}