专业编程基础技术教程

网站首页 > 基础教程 正文

一文总结C++的dynamic_cast 和 static_cast

ccvgpt 2024-10-12 13:56:33 基础教程 6 ℃

一、开篇

dynamic_caststatic_cast属于类型转换的范畴,准确的是显式类型转换,本文主要总结C++中的显式类型转换。

一个命名的强制类型转换有如下的格式:

一文总结C++的dynamic_cast 和 static_cast

cast_name<type>(expression)

上述格式中:

  • type:是转换的目标类型。
  • expression:是要转换的值。
  • cast_name:是类型转换的方式。有四种:static_catdynamic_castconst_castreinterpret_cast

二、static_cast类型转换

static_cast具有很广的使用场景:在类型转换中,只要不包含底层const,任何具有明确定义的类型转换,都可以使用static_cast。使用范围虽广,但是还需要根据具体的转换风险来选择,因为强制类型转换,本质上是一个危险的操作

【低风险转换】

空指针转换为任何目标类型的指针之间的转换

字符与整型之间的转换

整型和浮点型之间的转换

运算符之间的转换

低于低风险转换,则可以使用static_cast进行。

【高风险转换】

不同类型指针之间的转换

不同类型的引用之间的转换

整型和指针之间的互相转换

对于以上风险较高的转换,则不能使用static_cast

【基类与派生类之间的转换】

子类转换成父类,可以使用static_cast

父类转换成子类,是一个不安全的操作,所以不能使用static_cast。这时候需要使用后文中的dynamic_cast类型转换来进行转换啦!

三、const_cast类型转换

对于const_cast类型转换来说,需要注意几点: (1)const_cast只能改变运算对象的底层const。

(2)只有const_cast类型转换能改变表达式的常量属性,其他的类型转换不能,如果使用,则会引发编译时错误!

(3)不能使用const_cast改变表达式的类型。

(4)如果对象是一个常量,我们使用了const_cast执行对该对象的写操作将会是一个未定义的后果!

以上四点,可以用以下代码来逐一解释:

const char *cp;

//只有const_cast类型转换能改变表达式的常量属性,其他的类型转换不能,如果使用,则会引发编译时错误!
static_cast<char *>(cp);

//不能使用const_cast改变表达式的类型。
const_cast<string>(cp);

const_cast常常用于有函数重载的上下文中

例如下列代码:

int getAge(Student *);
int getAge(const Student *)

上述两个函数是重载函数,在实际工程中,编译器可以根据实参是否是常量来推断应该调用哪个函数,因为const不能转换成其他类型,所以只能把const修饰的对象传递给带有const形参。

四、reinterpret_cast类型转换

reinterpret_cast为运算对象的位模式提供较低层次上的重新解释。在《C++ Primer》一书中明确指出使用reinterpret_cast是非常危险的操作。

reinterpret_cast本质上依赖于具体的机器。要想安全的使用reinterpret_cast必须对涉及的类型和所使用的编译器实现转换的过程都非常了解。

综上,在实际C++使用中,如果没有足够的把握,避免使用reinterpret_cast进行类型转换。

五、dynamic_cast类型转换

dynamic_cast是运行时类型识别(RTTI)。该运算符用于:将基类的指针或引用安全的转换成派生类的指针或引用。该种类型转换适用于:当我们想使用基类对象的指针或引用执行某个派生类操作并且该操作不是虚函数。(一般说来,我们应该尽可能的使用虚函数)

dynamic_cast运算符的使用形式有以下三种:

dynamic_cast<type*>(e)

dynamic_cast<type&>(e)

dynamic_cast<type&&>(e)

type必须是一个类类型,并且通常情况下该类型应该有虚函数。在上述第一种形式中,e必须是一个有效的指针。第二种形式中,e必须是一个左值;在第三种形式中,e不能是左值。

在使用dynamic_cast中,应该对转换后的结果进行检查。避免转换失败!

转换的对象有指针和引用:

(5-1)指针类型的dynamic_cast

对于指针类型的dynamic_cast,当转换失败,其转换值为0,我们可以根据转换后结果值是否为0判断转换是否成功!

dynamic_cast使用方法如下:

void funCast(BaseClass *bc)
{
  if(MyClass *mc = dynamic_cast<BaseClass*>(bc))
  {
    //转换成功
    //...
  }
  else
  {
    //转换失败情况处理
    //...
  }

}

可以对一个空指针执行dynamic_cast,其转换结果为所需类型的空指针。

(5-2)引用类型的dynamic_cast

对于引用类型的dynamic_cast,当类型转换失败,程序会抛出一个std::bad_cast的异常,该异常定义在typeinfo标准库文件中。我们可以使用类似下列的代码来捕获这个异常:

void funCast(const BaseClass &bc)
{
  try
  {
    const MyClass &mc = dynamic_cast(BaseClass&)(bc);
    
    //后续操作
  }
  catch(std::bad_cast)
  {
    //处理类型转换失败的情况
  }

}

六、总结

类型检查,在实际开发中是一种有效规避错误的方式,主要由编译构建完成,程序越复杂,静态类型检查越能发挥巨大作用。然而强制类型转换干扰了正常的类型检查,因此在实际的开发中,尽量避免使用强制类型转换,规则如下:

(1)对于reinterpret_cast:不要使用。

(2)对于const_cast:在有重载函数的上下文中使用const_cast无可厚非。在其他情况下使用const_cast则证明该处程序存在设计缺陷。

(3)对于static_castdynamic_cast:不应该频繁使用。

【注】在代码中,每次书写了强制类型转换,都应该仔细斟酌是否有替代方式实现相同的目标。如果无法避免,应该尽量限制强制类型转换值的作用域。

最近发表
标签列表