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

news/2024/7/3 13:16:00 标签: 多态, class
class="baidu_pl">
class="article_content clearfix">
class="markdown_views prism-tomorrow-night">

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

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

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

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

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

class="prettyprint">class=" hljs lasso">class="hljs-comment">// C++ 5.2.7p1: T shall be a pointer or reference to a complete class type,
class="hljs-comment">//   or "pointer to cv void".

   QualType DestPointee;
   const PointerType class="hljs-subst">*DestPointer class="hljs-subst">= DestTypeclass="hljs-subst">->getAsclass="hljs-subst"><PointerTypeclass="hljs-subst">>();
   const ReferenceType class="hljs-subst">*DestReference class="hljs-subst">= nullptr;
   class="hljs-keyword">if (DestPointer) {
     DestPointee class="hljs-subst">= DestPointerclass="hljs-subst">->getPointeeType();
   } class="hljs-keyword">else class="hljs-keyword">if ((DestReference class="hljs-subst">= DestTypeclass="hljs-subst">->getAsclass="hljs-subst"><ReferenceTypeclass="hljs-subst">>())) {
     DestPointee class="hljs-subst">= DestReferenceclass="hljs-subst">->getPointeeType();
   } class="hljs-keyword">else {
     class="hljs-built_in">Selfclass="hljs-built_in">.Diag(OpRangeclass="hljs-built_in">.getBegin(), diagclass="hljs-tag">::err_bad_dynamic_cast_not_ref_or_ptr)
       class="hljs-subst"><< thisclass="hljs-subst">->DestType class="hljs-subst"><< DestRange;
     SrcExpr class="hljs-subst">= ExprError();
     class="hljs-keyword">return;
   }

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

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

class="prettyprint">class=" hljs php">class="hljs-comment">// C++ 5.2.7p5
   class="hljs-comment">// Upcasts are resolved statically.
   class="hljs-keyword">if (DestRecord && class="hljs-keyword">Self.IsDerivedFrom(SrcPointee, DestPointee)) {
     class="hljs-keyword">if (class="hljs-keyword">Self.CheckDerivedToBaseConversion(SrcPointee, DestPointee,
                                            OpRange.getBegin(), OpRange, 
                                            &BasePath)) {
       SrcExpr = ExprError();
       class="hljs-keyword">return;
     }

     Kind = CK_DerivedToBase;
     class="hljs-keyword">return;
   }

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

否则就需要操作数类型是class="tags" href="/tags/DuoTai.html" title=多态>多态类型,如下代码所示:

class="prettyprint">class=" hljs coffeescript">class="hljs-regexp">// C++ class="hljs-number">5.2class="hljs-number">.7: Otherwise, v shall be [polymorphic].
   class="hljs-reserved">const RecordDecl *SrcDecl = SrcRecord->getDeclclass="hljs-function">class="hljs-params">()->getDefinition();
   assert(SrcDecl && class="hljs-string">"Definition missing");
   class="hljs-keyword">if class="hljs-function">class="hljs-params">(!cast<CXXRecordDecl>(SrcDecl)->isPolymorphic()) {
     class="hljs-title">Self.class="hljs-title">Diagclass="hljs-params">(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_polymorphic)
       << class="hljs-title">SrcPointee.class="hljs-title">getUnqualifiedTypeclass="hljs-params">() << class="hljs-title">SrcExpr.class="hljs-title">getclass="hljs-params">()->getSourceRange();
     SrcExpr = ExprError();
   }
   class="hljs-regexp">// dynamic_cast class="hljs-keyword">is class="hljs-keyword">not available class="hljs-reserved">with -fno-rtti.
   class="hljs-regexp">// As an exception, dynamic_cast to class="hljs-reserved">void* class="hljs-keyword">is available because it doesnt
   class="hljs-regexp">// use RTTI
   class="hljs-keyword">if (!Self.getLangOpts().RTTI && !DestPointee->isVoidType()) {
     Self.Diag(OpRange.getBegin(), class="hljs-attribute">diag::err_no_dynamic_cast_with_fno_rtti);
     SrcExpr = ExprError();
     class="hljs-keyword">return;
   }

   class="hljs-regexp">// Done. Everything class="hljs-keyword">else class="hljs-keyword">is run-time checks.
   Kind = CK_Dynamic;

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

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


http://www.niftyadmin.cn/n/1428344.html

相关文章

手把手安装VirtualBox增强工具进行相关配置

之前没有用过虚拟机&#xff0c;现在突然开始使用虚拟机有很多不习惯&#xff0c;首先发现的是跨平台不能复制粘贴、已经不能互相丢文件&#xff0c;所以网上找了很多方法。发现最好用的就是安装一个增强工具&#xff0c;但是也遇到了很多与别人不一样的问题&#xff0c;踩了很…

static_cast能够适用所有转型吗,有什么条件

CheckStaticCast - Check that a static_cast(SrcExpr) is valid.Refer to C 5.2.9 for details. Static casts are mostly used for making implicit conversions explicit and getting rid of data loss warnings.—[Clang源码] 由Clang源码”CheckStaticCast()”函数中关于s…

java -- 异常机制

摘自《代码阅读》 前言 异常机制可用来将 错误处理代码 从程序正常控制流中分离出来。 java中异常是语言的一部分。能够沿着程序的词法和函数&#xff08;或方法&#xff09;的调用栈进行传播&#xff0c;并且可以结构化的方式进行处理。 1.java异常处理代码组成部分 try块中…

ArrayList源码全分析(初版)

ArrayList源码分析 前情提要&#xff1a;作为一个初学Java的人&#xff08;之前都是用C写代码的&#xff0c;但是为了找互联网开发岗位&#xff0c;最近一个月在恶补Java的知识&#xff09;&#xff0c;因为个人对源码比较感兴趣&#xff08;感兴趣不代表能正确解释所有源码&a…

static_cast在CRTP中的应用

CRTP是C中实现静态多态(static polymorphism)的方式&#xff0c;这种实现方式能够提高运行时效率及减少内存消耗&#xff0c;在嵌入式领域相当有优势。这里估计会有人反驳&#xff0c;难道针对每个派生类实例化独有的基类难道不占有内存吗&#xff1f; 编译时&#xff0c;实例…

eclipse编译问题

1.在java ( 或者是eclipse下) 中进行编译时编译了哪些内容&#xff1f; 得到编译的内容&#xff1a;&#xff08;1&#xff09;自己书写的源代码 未得到编译内容&#xff1a; &#xff08;2&#xff09;第三方jar包&#xff08;早已经编译&#xff09; ( 3 )java本身库&…

C++一种智能指针的实现

引子 C智能指针shared_ptr<>以对象管理资源一种智能指针的实现 C智能指针shared_ptr<> 为了兼容C语言&#xff0c;并且由于垃圾回收的性能原因&#xff0c;C没有引入垃圾回收。但是动态内存分配又是现实编码中不可或缺的一部分&#xff0c;由程序员自己控制分配…

Soot -- 路径问题

1.Soot 路径 Soot中的相对路径是相对自己而言的&#xff0c;而不是相对于java的。soot中路径如下图 &#xff08;摘自soot官方 https://github.com/Sable/soot/wiki/Tutorial&#xff09;&#xff1a; &#xff08;1&#xff09;soot这样安排路径也是合理的&#xff0c;毕竟这…