dynamic_cast 类型转换全面深入讨论
理解dynamic_cast,必须明白C++语言中继承和多态概念以及实现,不然无法真正明白其要求。
1.dynamic_cast在继承情况要求
dynamic_cast 只能在对象的引用和指向对象指针情况下, 目的是确保类型转换是一个有效完整转换类对象,因此当到基类转换(向上转换),dynamic_cast总是成功的。
限制条件说明:
1.针对对象之间装换
2.针对对象存在继承关系。
3.编译时检查
4.检查转换必须是有效完整的。例如人是基类,学生派生类,学生到人装换是有效的(学生具体人的所有特征), 但是人到学生转换不一定有效(一个人不一定具备学生特征)。
class CBase { };
class CDerived: public CBase { };
int main()
{
CBase b; CBase* pb;
CDerived d; CDerived* pd;
pb = dynamic_cast<CBase*>(&d); // 正确: 派生类到基类转换
pd = dynamic_cast<CDerived*>(&b); // 错误: 基类到派生类转换
}
编译时检查
# g++ xxx.cpp
xxx.cpp: In function ‘int main()’:
xxx.cpp:9: 错误:无法将‘& b’从类型‘CBase*’动态转换到类型‘class CDerived*’(source type is not polymorphic)
2.dynamic_cast在多态情况要求
当一个类是多态时(虚函数实现多态特性),dynamic_cast运行时执行特殊检查来确保产生一个一个有效完整转换类对象。
1.针对对象存在多态关系.(必须有虚函数)
2.运行时执行检查。
3.检查转换必须是有效完整的(要求指针或者引用对象必须是完整转换类对象),下面例子
#include <iostream>
#include <exception>
using namespace std;
class CBase { virtual void dummy() {} };
class CDerived: public CBase { int a; };
int main () {
try {
CBase * pba = new CDerived;// pba是一个完整的CDerived对象
CBase * pbb = new CBase;//pbb不是一个完整的CDerived对象
CDerived * pd;
//CDerived ≺
pd = dynamic_cast<CDerived*>(pba);
if (pd==0) cout << "Null pointer on first type-cast" << endl;
pd = dynamic_cast<CDerived*>(pbb);//指针转换 pbb(CBase)不是完整派生类(CDerived)对象,失败返回值为NULL
if (pd==0) cout << "Null pointer on second type-cast" << endl;
CDerived &pr = dynamic_cast<CDerived&>(*pbb);//引用转换,pbb(CBase)不是完整派生类(CDerived)对象,失败抛出异常
} catch (exception& e) {cout << "Exception: " << e.what();}
return 0;
}
运行时检查
# g++ yyy.cpp
# ./a.out
Null pointer on second type-cast
Exception: std::bad_cast