游戏电视苹果数码历史美丽
投稿投诉
美丽时装
彩妆资讯
历史明星
乐活安卓
数码常识
驾车健康
苹果问答
网络发型
电视车载
室内电影
游戏科学
音乐整形

CRTTI和四种类型转换

  RTTI是RunTimeTypeInformation的缩写,从字面上来理解就是执行时期的类型信息,其重要作用就是动态判别执行时期的类型。
  并不是说这篇文章是RTTI,和用于RTTI的四种类型转换,而是介绍RTTI,再介绍一下4种类型转换,因为RTTI有用到其中一种类型转换,所以相当于两篇文章写在一起。
  实际上RTTI用到的是typeid()和dynamiccast()。
  为什么会有RTTI?
  C是一种静态类型语言,其数据类型是在编译期就确定的,不能在运行时更改。然而由于面向对象程序设计中多态性的要求,C中的指针或引用(Reference)本身的类型,可能与它实际代表(指向或引用)的类型并不一致。有时我们需要将一个多态指针转换为其实际指向对象的类型,就需要知道运行时的类型信息,这就产生了运行时类型识别的要求。
  实事求是地讲,RTTI是有用的。但因为一些理论上及方法论上的原因,它破坏了面向对象的纯洁性。
  首先,它破坏了抽象,使一些本来不应该被使用的方法和属性被不正确地使用。
  其次,因为运行时类型的不确定性,它把程序变得更脆弱。
  第三点,也是最重要的一点,它使程序缺乏扩展性。当加入了一个新的类型时,你也许需要仔细阅读你的dynamiccast的代码,必要时改动它们,以保证这个新的类型的加入不会导致问题。而在这个过程中,编译器将不会给你任何帮助。
  总的来说,RTTI因为它的方法论上的一些缺点,它必须被非常谨慎地使用。今天面向对象语言的类型系统中的很多东西就是产生于避免RTTI的各种努力。
  首先我们来个例子感受一下:includeiostreamincludetypeinfousingnamespacestd;classBase{public:virtualvoidfuncA(){coutBaseendl;}};classDerived:publicBase{public:virtualvoidfuncB(){coutDerivedendl;}};voidfuncC(Basep){DeriveddpdynamiccastDerived(p);if(dp!NULL){dpfuncB();}else{pfuncA();}};voidfuncD(Basep){DeriveddpNULL;if(typeid(p)typeid(Derived)){dpstaticcastDerived(p);dpfuncB();}else{pfuncA();}}intmain(intargc,charconstargv〔〕){BasepnewDerived;couttypeid(p)。name()endl;couttypeid(p)。name()endl;funcD(p);funcC(p);deletep;BasedpnewBase;funcC(dp);funcD(dp);deletedp;return0;}
  funcC是用dynamiccast类型转换是否成功来识别类型的,dynamiccast操作符将基类类型对象的引用或指针转化为同一继承层次中的其他类型的引用或指针。
  如果绑定到引用或指针的对象不是目标类型的对象,则dynamiccast失败。
  如果转换到指针类型的dynamiccast失败,则dynamiccast的结果是NULL值;
  如果转换到引用类型的dynamiccast失败,则抛出一个badcast类型的异常
  funcD是用typeid判断基类地址是否一致的办法来识别类型的。typeid
  下面我们具体说说typeid
  typeid是C的关键字之一,等同于sizeof这类operator。typeid操作符的返回结果是名为typeinfo的标准库类型的对象的引用,在头文件typeinfo中定义。有两种形式:typeid(type)typeid(expression)
  表达式的类型是类类型,且至少含有一个虚函数,则typeid操作符返回表达式的动态类型,需要在运行时计算,否则返回表达式的静态类型,在编译时就可以计算。
  C标准规定了其实现必须提供如下四种操作:t1t2:如果两个对象t1和t2类型相同,则返回true;否则返回falset1!t2:如果两个对象t1和t2类型不同,则返回true;否则返回falset。name():返回类型的cstyle字符串,类型名字用系统相关的方法产生t1。before(t2):返回指出t1是否出现在t2之前的bool值
  typeinfo类提供了public虚析构函数,以使用户能够用其作为基类。它的默认构造函数和复制构造函数及赋值操作符都定义为private,所以不能定义或复制typeinfo类型的对象。程序中创建typeinfo对象的唯一方法是使用typeid操作符。由此可见,如果把typeid看作函数的话,其应该是typeinfo的友元。这具体由编译器的实现所决定,标准只要求实现为每个类型返回唯一的字符串。
  例1:C里面的typeid运箕符返回值是什么?
  答:常量对象的引用。
  如果p是基类指针,并且指向一个派生类型的对象,并且基类中有虚函数,那么typeid(p)返回p所指向的派生类类型,typeid(p)返回基类类型。
  RTTI的实现原理:通过在虚表中放一个额外的指针,每个新类只产生一个typeinfo实例,额外指针指向typeinfo,typeid返回对它的一个引用。staticcast
  staticcastnewtype(expression)
  本来应该先讨论dynamiccast的,因为咱们本来聊的RTTI嘛,但是先了解一下staticcast,然后看和dynamiccast的比较可能更好一点。
  使用场景:基本数据类型之间的转换initializingconversionintnstaticcastint(3。14);coutnn;vectorintvstaticcastvectorint(10);coutv。size()v。size();类指针或引用向下转换。将类型转为右值类型,进行move操作,这个在标准库中有体现(放在下一篇文章中解释)vectorintvstaticcastvectorint(10);vectorintv2staticcastvectorint(v);coutaftermove,v。size()v。size();coutv。size()endl;子类数组指针向上转成父类的指针structB{intm0;voidhello()const{coutHelloworld,thisisB!;}};structD:B{voidhello()const{coutHelloworld,thisisD!;}};Da〔10〕;BdpstaticcastB(a);dphello();枚举转换成intorfloatenumE{ONE1,TWO,THREE};EeE::ONE;intonestaticcastint(e);coutone;inttoenum,enumtoanotheremumenumclassE{ONE1,TWO,THREE};enumEU{ONE1,TWO,THREE};EeE::ONE;intonestaticcastint(e);Ee2staticcastE(one);EUeustaticcastEU(e2);voidtoanytypeinta100;voidvoidpa;intpstaticcastint(voidp);
  注意:staticcast不能转换掉expression的const、volatile和unaligned属性,编译器隐式执行任何类型转换都可由staticcast显示完成dynamiccast
  dynamiccastnewtype(expression)
  接下来是dynamiccast:
  动态映射可以映射到中间层级,将派生类映射到任何一个基类,然后在基类之间可以相互映射。
  dynamiccast实现原理:先恢复源指针的RTTI信息,再取目标的RTTT信息,比较两者是否相同,不同取目标类型的基类;由于它需要检查一长串基类列表,故动态映射的开销比typeid大。
  dynamiccast的安全性:如实现原理所说,dynamiccast会做一系列的类型检查,转换成功会返回目标类型指针,失败则会返回NULL,相对于staticcast安全,因为staticcast即使转换失败也不会返回NULL。
  例2:这种情况下staticcast()也是安全的。classBase{public:voidfunc(){coutBasefuncendl;}};classDerived:publicBase{public:voidfunc(){coutDerivedfuncendl;}};intmain(intargc,charconstargv〔〕){DerivedpdnewDerived;pdfunc();Basepb1dynamiccastBase(pd);pb1func();Basepb2staticcastBase(pd);pb2func();return0;}
  pd指针指向的内存是子类对象,我们知道,继承子类是包含父类的,相当于在父类的基础上在添加子类的成员(如果你还不清楚的话,建议你看一下我之前的文章:虚函数,虚表深度剖析)。所以pd指针转成父类指针也是没问题的,staticcast也一样安全。
  相反,如果指针指向的内存是父类成员,转成子类指针,dynamiccast则会失败,返回NULL,但是staticcast不会失败,强制转过去了,如果此时子类指针访问父类中不存在,但是子类中存在的成员,则会发生意想不到的问题。
  看下面这个例子:classBase{public:virtualvoidfunc(){coutBasefuncendl;}};classDerived:publicBase{public:virtualvoidfunc(){coutDerivedfuncendl;}intmvalue0;};intmain(intargc,charconstargv〔〕){BasepbnewBase;pbfunc();Derivedpd1dynamiccastDerived(pb);if(pd1!NULL){pd1func();}else{coutdynamiccastfailedendl;}Derivedpd2staticcastDerived(pb);pd2func();coutmvalue:pd2mvalueendl;return0;}
  输出:BasefuncdynamiccastfailedBasefunc父类中也有这个虚函数,所以staticcast转换调用没出问题。mvalue:33686019这里出问题了
  对于上行转换,staticcast和dynamiccast效果一样,都安全,如果只是单纯的向上转的话,没必要,直接用虚函数实现就好了。
  对于下行转换:你必须确定要转换的数据确实是目标类型的数据,即需要注意要转换的父类类型指针是否真的指向子类对象,如果是,staticcast和dynamiccast都能成功;如果不是staticcast能返回,但是不安全,可能会出现访问越界错误,而dynamiccast在运行时类型检查过程中,判定该过程不能转换,返回NULL。constcast
  constcastnewtype(expression)
  上面讲了staticcast是不能去掉const,而constcast是专门用来去掉const。
  而添加const,staticcast也是可以添加上const,只是不能去掉const
  看下面一个例子:constinta26;constintpaa;pa3;编译不过,指针常量不能通过指针修改值intbconstcastint(pa);把const转换掉b3;couta:aendl;26coutb:bendl;3
  a为constint类型,不可修改,pa为constint类型,不能通过pa指针修改a的值
  b通过constcast转换掉了const,成功修改了a的值。
  有一个问题,为什么a输出是26呢?
  如果存在constintx26;这种情况,那么编译器会认为x是一个编译期可计算出结果的常量,那么x就会像宏定义一样,用到x的地方会被编译器替换成26。
  上述这个例子不建议使用,因为a声明为constint类型,实际上是并不希望被修改的,这样强行修改可能会导致项目里不可预期的错误。
  constcast的使用场景如果有一个函数,它的形参是nonconst类型变量,而且函数不会对实参的值进行改动,这时我们可以使用类型为const的变量来调用函数。voidfunc(inta){}intmain(){constinta26;constintpaa;func(constcastint(pa));}
  这种情况其实我觉得没必要,实际上我不想改的话,我形参加const,把前提推翻不就行了,还安全。定义了一个nonconst的变量,却使用了一个指向const值的指针来指向它(这不是没事找事嘛),在程序的某处我们想改变这个变量的值了,但手头只持有指针,这时constcast就可以用到了inta26;constintpaa;pa1;编译不过intpa2constcastint(pa);pa21;reinterpretcast
  reinterpretcastnewtype(expression)
  reinterpretcast通常为操作数的位模式提供较低层的重新解释。
  看这个例子:intn9;doubledstaticcastdouble(n);coutnd;输出99intn29;doubled2reinterpretcastdouble(n2);coutn2d2;输出99。25596e61
  上面的例子中,我们将一个变址从int转换到double。这些类型的二进制表达式是不同的。要将整数9转换到双精度整数9,staticcast需要正确地为双精度整数d补足比特位。其结果为9。0。
  而reinterpretcast的行为却不同,仅仅是把内存拷贝到目标空间,解释出来是一个大数。
  reinterpretcast这个操作符被用于的类型转换的转换结果几乎都是未知的。
  使用reinterpretcast的代码很难移植。转换函数指针的代码是不可移植的,(C不保证所有的函数指针都被用一样的方法表示),在一些情况下这样的转换会产生不正确的结果。所以应该避免转换函数指针类型,按照C新思维的话来说,reinterpretcast是为了映射到一个完全不同类型的意思,这个关键词在我们需要把类型映射回原有类型时用到它。
  我们映射到的类型仅仅是为了故弄玄虚和其他目的,这是所有映射中最危险的。reinterpretcast就是一把锐利无比的双刃剑,除非你处于背水一战和火烧眉毛的危急时刻,否则绝不能使用。
  其实reinterpretcast用法细节还有不少,什么时候需要用到,再去官方了解一下就好了,现在纠的太细意义不大。

铃木电动化战略虽迟但到!可市场还等得住吗?电动汽车这张牌,铃木终于打出来了。近日,据外媒报道,铃木计划于2025年推出首款电动汽车,并将在印度率先上市,随后在日本和欧洲销售。随着铃木进入电动汽车赛道,日本所有主要……原本以为3060可以缓解显卡价格上涨的趋势最终还是徒劳无功显卡价格上涨已到了肆无忌惮的地步了,原本以为RTX3060的发布可以缓解下当前显卡市场的压力,毕竟刚开始公布的时候是阉割了一半的挖矿性能的,这对于矿老板来说跟本没啥用下,但对于……知产晨报腾讯群组合并专利获授权,韩国拟立法对抗谷歌苹果垄断8月25日知识产权快讯1hr专利腾讯群组合并专利获授权,N个微信群或能合并8月24日,腾讯科技(深圳)有限公司获得会话群组的合并方法、装置、终端及存储介质专利……我为群众办实事,志愿服务暖人心中建一局二公司四川分公司开展志愿者服务活动为践行我为群众办实事实践活动,中建一局二公司于8月30日组织员工前往成都市双流区秦东社区参加疫苗接种志愿者服务活动。志愿者……足额支付!18苏宁03债券按期完成回售6月10日,苏宁易购发布公告称,18苏宁03债券按期完成回售,本金及利息已足额支付。市场分析人士指出,近期苏宁连续兑付债券,体现了公司对未来发展的信心,保障投资人利益,有……千元智能音箱的天花板,华为sound音箱值得拥有智能音箱,是这几年智能家居中最火热产品之一,尤其是众多互联网公司涌入,纷纷谋求作为智能家居的入口。百度、天猫、小米智能音响成为国内音箱的三大巨头,但是,他们均有一个通病,就是重……饿了么被超开两倍,最初的口号已经失败,准备卷土重来外卖是近几年来十分火热的一个词语,大大小小的城市中都已经可以看到黄蓝两道身影,骑着电动车,背着保温箱在大街小巷中送餐。而我们外卖经过几年前的腥风血雨,市场的大部分已经被饿了么和……内心上演了一出又一出的大戏中午和同事一起去吃饭,选好菜后,直接端着餐盘去打饭,跟着同事找位置去了。到位置后,才反应过来,刚才自己忘记去称菜了,忘记付钱了(我们吃的是【大米先生】:有很多种菜放在那里……如何延缓液晶拼接屏在使用过程中的逐渐老化众所周知,凡是电子产品都是有使用寿命的,液晶拼接屏也不例外。虽然从数据上来看,液晶拼接屏的大概使用寿命约为6万8万小时,但是由于应用环境、功能通途、人为损坏等等因素的参与,其实……小鹏P5亮剑上海车展,率先搭载激光雷达自动驾驶4月19日,小鹏汽车携旗下第三款产品,全球首款搭载激光雷达的量产智能汽车小鹏P5亮相2021上海车展,并宣布小鹏P5正式开启预订。小鹏汽车董事长CEO何小鹏与所有到场嘉宾举办以……小猪佩奇是驰名商标?一公司涉嫌侵权被罚3万3月18日,近日,上海市知识产权法院(下称上海知产法院)审结原告娱乐壹英国有限公司(下称娱乐壹公司)与被告陈某某、上海寻梦信息技术有限公司(下称寻梦公司)侵害商标权纠纷案。……星际争霸II新短篇故事分享同民同心作者:AlexAcks编辑:ChloeFraboni出品人:BrianneMessina背景顾问:MadiBuckingham,SeanCopeland……
烈火如歌刀冽香扮演者代斯惊艳亮相佳人如斯古装玄幻剧《烈火如歌》由周渝民、迪丽热巴、张彬彬、刘芮麟主演,将于2018年3月1日在优酷播出。《烈火如歌》讲述了烈火山庄的继承人烈如歌(迪丽热巴饰演),与在她生命中扮演不同重……腾讯RoboticsX实验室四足移动机器人Jamoca首亮相11月20日,腾讯公布了其在移动机器人研究方面的新进展:四足移动机器人Jamoca和自平衡轮式移动机器人首次对外亮相。Jamoca是国内首个能完成走梅花桩复杂挑战的四足机……刑侦大剧燃烧今晚开播经超主演挑大梁上演隔代追凶星关系5月28日讯今日,由陈育新执导,经超、张佳宁,奚美娟、谭凯、邬君梅,林籽,崔绍涵,张峻鸣、刘敏涛、张志坚,冯雷、汤镇宗、杜志国、公磊、林乐炫等主演的刑侦剧《燃烧》将于北京……一千零一夜昨晚完美收官!陈奕龙力挽狂澜促成完美结局星关系讯:昨晚,陪伴了大家一个盛夏的热播电视剧《一千零一夜》迎来大结局,其中,陈奕龙饰演的莫南,也成为剧情走势的关键,在经历了复仇的痛苦之后,最终与七七和解,并决定和柏海联手夺……一千零一夜浪漫收官邓伦颜值实力双获好评星关系讯:由邓伦主演的电视剧《一千零一夜》于昨晚在湖南卫视正式收官,自开播以来,该剧一直备受关注,并以绝佳的成绩频频卫冕同时段收视率第一。《一千零一夜》讲述了柏海和凌凌七因花结……一千零一夜剧情升温!陈奕龙为爱成全上演虐心戏《一千零一夜》剧情升温!陈奕龙为爱成全上演虐心戏近日,热播剧《一千零一夜》已播放过半,在莫南的间谍身份爆出后,在本周即将迎来又一段剧情高潮!该剧编剧也在微博中透露,只会虐……疯狂打脸!特斯拉ampquot完全ampquot自动驾驶大话特斯拉的全自动驾驶长期以来一直是其最雄心勃勃和最具争议的功能,但现在看来,特斯拉可能正在背离其最初的雄心壮志。3月8日,TeslaMotorsClub的会员lunitiks发现……电视剧一千零一夜今日开播小白陈奕龙再度上演暖心追爱《一千零一夜》今日开播小白陈奕龙再度上演暖心追爱今日,由迪丽热巴、邓伦、陈奕龙等主演的电视剧《一千零一夜》将在湖南卫视金鹰独播剧场迎来首播,一场梦境和现实的碰撞,一段唯美……5月20日起,微信将不再提供这项服务日前微信开放社区宣布2021年5月20日之后不再提供小程序打开App技术服务微信称,微信小程序为开发者提供了打开App的技术服务,希望通过开发者的……海上嫁女记热播陈奕静背叛王雷折腾蔡少芬近日,由林黎胜、黄永刚执导,蔡少芬、王雷、张檬、陈奕静联袂出演的都市情感剧《海上嫁女记》正在安徽卫视海豚第一剧场热播中,该剧主要讲述了一个事业成功、充满人格魅力的70后母亲,与……棋逢对手or差异明显?主流合资B级车最强对决每到年底,都会迎来新一轮的购车热潮,辛苦工作一年,买辆车来犒劳下自己,过年回家面对亲戚朋友也更体面,加之年底的金融政策也会相对更加给力,很多消费者都会选择在这个时间段来购车。既……贝莱德仍在ampampquot研究ampampquot比特币贝莱德的首席执行官拉里芬克今天谈到了比特币的波动性。这位首席执行官此前已对加密货币表现出兴趣。他说,对于这个全球最大的资产管理公司来说,现在投资还为时过早。据报道,全球最……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网