dynamic_cast<>操作数必须是多态类型吗

dynamic_cast<>是C++运行时的一个类型转换运算符,通常用于自定义类型层次中的向下转型(downcasts),使用形式如下所示:

  • dynamic_cast<type*>(e)
  • dynamic_cast<type&>(e)
  • dynamic_cast<type&&>(e)

根据Primer中的解释,type必须是一个类类型,并且通常情况下该类型应该含有虚函数,即该类型是多态类型。也就是说有少数情况是不需要type为多态类型,这种情况就是派生类指针向基类指针的类型转换dynamic_cast<Base*>(Derived*),这种转换不需要用到运行时信息RTTI,在编译时期就可以通过操作数的类型来判断转型是否合法。

编译器Clang源码,SemaCast.cpp中CheckDynamicCast()函数对dynamic_cast<>的使用语义进行了很好的体现。

dynamic_cast(srctype)中type类型必须是指针或者引用。

// C++ 5.2.7p1: T shall be a pointer or reference to a complete class type,
//   or "pointer to cv void".

   QualType DestPointee;
   const PointerType *DestPointer = DestType->getAs<PointerType>();
   const ReferenceType *DestReference = nullptr;
   if (DestPointer) {
     DestPointee = DestPointer->getPointeeType();
   } else if ((DestReference = DestType->getAs<ReferenceType>())) {
     DestPointee = DestReference->getPointeeType();
   } else {
     Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ref_or_ptr)
       << this->DestType << DestRange;
     SrcExpr = ExprError();
     return;
   }

其中590行和592行要求DestType必须是指针或者引用类型。

另外,dynamic_cast(srctype)中srctype的类型要求。

// C++ 5.2.7p5
   // Upcasts are resolved statically.
   if (DestRecord && Self.IsDerivedFrom(SrcPointee, DestPointee)) {
     if (Self.CheckDerivedToBaseConversion(SrcPointee, DestPointee,
                                            OpRange.getBegin(), OpRange, 
                                            &BasePath)) {
       SrcExpr = ExprError();
       return;
     }

     Kind = CK_DerivedToBase;
     return;
   }

如果是向上转型(upcasts)的话,转换就会静态决议,也就是在编译阶段就能确定,不会耗费运行时的信息。

否则就需要操作数类型是多态类型,如下代码所示:

// C++ 5.2.7: Otherwise, v shall be [polymorphic].
   const RecordDecl *SrcDecl = SrcRecord->getDecl()->getDefinition();
   assert(SrcDecl && "Definition missing");
   if (!cast<CXXRecordDecl>(SrcDecl)->isPolymorphic()) {
     Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_polymorphic)
       << SrcPointee.getUnqualifiedType() << SrcExpr.get()->getSourceRange();
     SrcExpr = ExprError();
   }
   // dynamic_cast is not available with -fno-rtti.
   // As an exception, dynamic_cast to void* is available because it doesnt
   // use RTTI
   if (!Self.getLangOpts().RTTI && !DestPointee->isVoidType()) {
     Self.Diag(OpRange.getBegin(), diag::err_no_dynamic_cast_with_fno_rtti);
     SrcExpr = ExprError();
     return;
   }

   // Done. Everything else is run-time checks.
   Kind = CK_Dynamic;

由于dynamic_cast<>需要RTTI信息,如果编译时关闭了RTTI的情况下使用dynamic_cast<>则会报错,但是一种情况除外,就是向void*的转换,因为不需要运行时信息。

dynamic_cast<>会在运行时执行类型安全的检查,自然会影响运行时的效率,该转换需要通过两次指针解引用获得type_info,然后再判断转换是否合法。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
static<>是C++中的一个强制类型转换操作符。它可以用于进行简单粗暴的类型转换,但其正确性完全由程序员自己保证。与C语言中的强制转换不同,static_cast会在编译时进行类型检查。它可以明确告诉编译器转换的目的,也可以让其他程序员清楚地知道转换的意图。static_cast可以进行精度大转精度小的转换,使用位截断来处理。此外,它还可以用于基类与派生类指针或引用类型之间的转换,但它不会做运行时的检查,因此相比dynamic_cast来说不那么安全。相比之下,dynamic_cast会遍历整个类继承体系进行类型检查,所以在执行效率上比static_cast要差一些。总而言之,static_cast是一个强制类型转换操作符,可用于进行各种类型的转换。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [static_cast 剖析](https://blog.csdn.net/qq_45853229/article/details/124721212)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [【C++】强制类型转换操作符 static_cast](https://blog.csdn.net/lemonxiaoxiao/article/details/121075537)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值