C++中的dynamic_cast

来源:互联网 发布:家庭ktv点歌软件 编辑:程序博客网 时间:2024/05/23 17:05
dynamic_cast有什么用?实际上,dynamic_cast是ANSI C++中仅有的两个与RTTI (Run Time Type Identification) 有关的用法之一。C++的类继承,使得有时很难弄清楚你正在使用的object属于哪个class,特别是当继承树比较深并且比较复杂的时候,例如,当你在程序中取得一个CWnd*指针,你的意图是,如果它实际上指向一个dialog对象那么就调用它的DoModal方法,这个时候,你就需要dynamic_cast:
 
CWnd* pWin = myGetWin();
CDialog* pDlg = NULL:
if( pDlg = dynamic_cast<CDialog*>(pWin) )
    pDlg->DoModal();
 
这里用简单的强制类型转换或者static_cast不行吗?确实是不行的。假如pWin实际指向的是一个View对象,你的程序就会对View对象调用DoModal(),在MFC里你这样做或许仅仅会得到一个Assert,有些场合会得到一个segment fault,而按照Effective C++里面的说法,这样undefined的用法,也许会导致这个程序向你热恋中的女友发一封绝交信,呵呵。如果是多线程的程序,这样的一个问题导致你花上一整天时间疯狂地打log是很正常的事情。
 
而使用dynamic_cast,如果实际对象不是CDialog,一个NULL指针会被传回来。就算你忘记了写if then,你也可以很快利用调试器定位出错误在哪里。NULL指针的bug大概是所有bug中最幸福的一种。
 
dynamic_cast做到这一点是利用了编译器提供的RTTI机制,编译器会把一个class的类型信息放在C++ Runtime系统的某处,常常就是在vtbl的末端,这样从class指针得到vptr,再从vptr得到vtbl,就能够检查类型信息是否匹配。
 
dynamic_cast的用法之所以少见,是因为它实际上是一种“不好的”用法,某种程度上破坏了O-O的一些基本原则。既然定义了一个基类类型,就是想把派生类的差异性隐藏起来,提供一个统一的interface,那么你又有什么理由再从外面把这种差异性还原出来呢?不止一本C++经典论述中提到过,在一个设计良好的类继承体系中,不该为dynamic_cast留下生存空间。
 
然而,圣经和实际生活总有距离,有时候架构不那么完美,只是把一堆对象用一个基类指针的数组管理起来,你必须使用某个派生类的特定方法,而类库又没有为你提供这样的路径,你就只好自己动手,把它解构。像上面给出的例子,很难说在实践中不会遇见这样的状况。
 
也许有人会说,这样的问题啊,我会自己处理的,用不着什么RTTI,我会为在基类中添加一个type数据成员,再做一个GetType()方法,每个派生类对象在构造的时候赋予不同的值,调用的时候判断一下,这不就OK了吗?这样做当然也可以,但是首先,你的实现效率比编译器的RTTI实现差远了,你要为每个object增加一个字的空间开销,而编译器则是对一个class增加一点空间,因为编译器可以利用现有的vptr和vtbl,你却没法控制C++ Runtime库。其次,退一万步讲,为什么要设计C++呢?完全可以用纯正的C程序实现类封装、继承、多态这些机制,无非就是用一堆函数指针嘛!早期的C++程序是怎么编译的?是用一个预处理器先翻译成C代码,再用C编译器去编译。用了C++,不就是为了少写一些代码,程序结构更清楚嘛。因此只要编译器提供这个功能,就不要再自己去找麻烦。
 
关于dynamic_cast最有趣的事情在于,主流的C++编译器为了满足一些吝啬的C程序员的要求,一般都提供了把RTTI关掉的编译选项,这样确实可以减少一些空间开销。而如果你使用了这样的编译选项,而你的程序中又使用了dynamic_cast,啊哈,美妙的segment fault立即就会向你袭来。
 
在不少mail-list中都可以看到有人在抱怨dynamic_cast引起的程序崩溃,其中一些使用g++的提问者还明白地知道自己加上了-fno-rtti的选项,回答问题的老大们就往往会用"foolish"来形容这样的行径。至于用Visual C++的人就更糟糕了,VC6中的cl编译器默认设定是关掉RTTI 的,你必须自己在project settings页面里把它选上,或者手工添加"/GR"选项。在Windows下面试图移植OpenH323类库的同道们,估计肯定有人吃过这个苦头。
 
最无辜的程序员是这样的,他认为使用ANSI C++标准中定义的东西怎么会有问题呢?但偏偏他遇到了一位热心的Build Master,为了优化性能把RTTI选项给关掉了。我想这个问题,是衡量一个软件开发队伍配置管理水平的一个经典题目。
 
 
此日志的引用通告 URL 是:
http://skywalkerj.spaces.live.com/blog/cns!49c467f1b758d6fc!146.entry?sa=20850098
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 十一个月宝宝不爱吃饭怎么办 14个月宝宝不爱吃饭怎么办 一岁宝宝喜欢哭怎么办 4岁儿童不会说话怎么办 8个月宝宝37.5度怎么办 8个月婴儿37.5度怎么办 5个月宝宝38度怎么办 5个月宝宝发烧怎么办 五个月小孩38度怎么办 宝宝3岁还不会说话 怎么办 两岁宝宝流口水厉害怎么办 两周宝宝不说话怎么办 两岁宝宝说话有点口吃怎么办 一周岁的宝宝脾气不好怎么办 九个月的宝宝脾气不好怎么办 两岁宝宝脾气不好怎么办 2岁宝宝脾气不好怎么办 3岁宝宝脾气不好怎么办 脾气不好吓到宝宝了怎么办 四个月宝宝脾气不好怎么办 5岁说话不清楚该怎么办 小孩快上幼儿园了不怎么说话怎么办 四岁宝宝吐字不清楚怎么办 孕28周胎儿腿短怎么办 b超显示腿短怎么办 2岁多宝宝不愿意说话怎么办 6岁儿童咬字不清怎么办 两岁宝宝爱看电视怎么办 两岁宝宝喜欢看电视怎么办 三岁宝宝说话不清晰怎么办 儿子快四岁了说话不清楚怎么办 儿子快三岁了说话不清楚怎么办 2岁宝宝受刺激了怎么办 一岁的宝宝口臭怎么办 古话说小孩牙齿掉了怎么办 宝宝三岁胆子小怎么办 小宝宝就是不愿意学说话怎么办 2岁宝宝体重偏重怎么办 三岁宝宝体重偏重怎么办 3岁宝宝说话晚怎么办 孩子吃饭总说话吃饭慢怎么办