C++多继承动态交叉转换dynamic_cast
来源:互联网 发布:网络鲜花速递 编辑:程序博客网 时间:2024/05/05 02:52
1. 问题简述:
有如下源代码:
Class BaseA;Class BaseB;Class SubClass:public BaseA,public BaseB{...}现有如下变量定义:
BaseA* insA = new SubClass(...);BaseB* insB;请问如何将insA指向的对象正确赋值给BaseB*的指针insB? 有下面两种方法:
- 既然我们知道insA是SubClass类型,可以先把父类的指针insA转换成子类的指针类型SubClass*,然后在上行转换成父类型BaseB:insB = (BaseB*)( ( SubClass* )insA)
- 调用C++的dynamic_cast函数,它会先做类型检查,以保证类型正确,如果不能转换,会出错:insB = dynamic_cast<BaseB*>(insA)
2. 例子剖析:
源代码:
#include <iostream>using namespace std;// class BaseA;// class BaseB;// class SubClass;class BaseA{private:int m_baseA;int m_moreSpace;public:BaseA(int a = 0){m_baseA = a;//lala = 34;m_moreSpace = 1111111;}virtual int getA(){return m_baseA;}virtual int getMoreSpace(){return m_moreSpace;}};class BaseB{private:int m_baseB;public:BaseB(int b = 0){m_baseB = b;}virtual int getB(){return m_baseB;}virtual int forA(){cout<<"\t+++++++++++++++++++++++++++++++++++++++++++++++++++"<<endl;cout<<"\tyou call me ,haha!"<<endl;cout<<"\t+++++++++++++++++++++++++++++++++++++++++++++++++++"<<endl;return 999999999;}};//先给BaseA开辟空间,然后给BaseB开辟数据空间,最后给自定义类开辟数据空间class SubClass:public BaseA,public BaseB{private:int m_subInt;public:SubClass(int sub = 0,int basea=0,int baseb=0):BaseB(baseb),BaseA(basea){m_subInt = sub;}int getSubInt(){// cout<<"SubClass:BaseA:getA()"<<getA()<<endl;// cout<<"SubClass:BaseB:getB()"<<getB()<<endl;return m_subInt;}};int main(){SubClass* ins = new SubClass(11,22,33);//a=22,b=33;cout<<"((SubClass*)ins) -> getSubInt():"<<((SubClass*)ins) -> getSubInt()<<endl;cout<<"c cast:\n\t(BaseA*)ins->getA():"<<((BaseA*)ins)->getA()<<endl; //22cout<<"c cast:\n\t(BaseB*)ins->getB():"<<((BaseB*)ins)->getB()<<endl; //33BaseA* insA = ins;cout<<"c cast:\n\t(BaseA*)insA->getA():"<<((BaseA*)insA)->getA()<<endl; //22cout<<"c cast:\n\t(BaseB*)insA->getB():"<<((BaseB*)insA)->getB()<<endl; //22BaseB* insB = ins;cout<<"c cast:\n\t(BaseA*)insB->getA():"<<((BaseA*)insB)->getA()<<endl; //33/*****************************************************************************************//* 如果A中的函数getMoreSpace为虚函数,那么此处会报错,因为insB中并没有第二个虚函数,如果B中有第二个虚函数的话, 就会调用B中的虚函数/*****************************************************************************************/cout<<"c cast:\n\t(BaseA*)insB->getMoreSpace():"<<((BaseA*)insB)->getMoreSpace()<<endl; //11,sub值,访问越界cout<<"c cast:\n\t(BaseB*)insB->getB():"<<((BaseB*)insB)->getB()<<endl; //33cout<<"using dynamic_cast.............................................."<<endl;/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*在使用dynamic_cast的时候,类型中一定要有虚函数,否则会编译报错*///////////////////////////////////////////////////////////////////////////cout<<"c++ cast:\n\t( dynamic_cast<BaseA*>(insA) )->getA():"<< ( dynamic_cast<BaseA*>(insA) ) -> getA()<<endl; //22cout<<"c++ cast:\n\t( dynamic_cast<BaseB*>(insA) )->getB():"<<( dynamic_cast<BaseB*>(insA) ) -> getB()<<endl; //33cout<<"c++ cast:\n\t( dynamic_cast<BaseA*>(insB) )->getA():"<< ( dynamic_cast<BaseA*>(insB) )->getA()<<endl; //22cout<<"c++ cast:\n\t( dynamic_cast<BaseB*>(insB) )->getB():"<<( dynamic_cast<BaseB*>(insB) )->getB()<<endl; //33cout<<"another choice:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"<<endl;cout<<"c cast:\n\t((BaseA*)( (SubClass*)insA ))->getA():"<< ((BaseA*)( (SubClass*)insA )) -> getA()<<endl; //22cout<<"c cast:\n\t((BaseB*)( (SubClass*)insA ))->getB():"<< ((BaseB*)( (SubClass*)insA )) -> getB()<<endl; //33cout<<"c cast:\n\t((BaseA*)( (SubClass*)insB ))->getA():"<< ((BaseA*)( (SubClass*)insB ))->getA()<<endl; //22cout<<"c cast:\n\t((BaseB*)( (SubClass*)insB ))->getB():"<< ((BaseB*)( (SubClass*)insB ))->getB()<<endl; //33return 0;};
运行结果:
逐行剖析:
cout<<"c cast:\n\t(BaseA*)ins->getA():"<<((BaseA*)ins)->getA()<<endl; //22cout<<"c cast:\n\t(BaseB*)ins->getB():"<<((BaseB*)ins)->getB()<<endl; //33由于ins是子类SubClass类型的指针,进行上行转换,C++会自动计算偏移量,假设ins的地址为0x00000000,那么(BaseA*)ins的地址也会是0x00000000,(BaseB*)ins的地址会是0x00000000+3*4(说明:BaseA两个数据成员加上一个虚函数表指针)
BaseA* insA = ins;cout<<"c cast:\n\t(BaseA*)insA->getA():"<<((BaseA*)insA)->getA()<<endl; //22cout<<"c cast:\n\t(BaseB*)insA->getB():"<<((BaseB*)insA)->getB()<<endl; //22
将ins赋值给BaseA类型的指针后,它就失去了作为BaseB之类的性质,在进行转换(BaseB*)insA的时候,它并不能计算偏移值,也就是说,(Base*)insA后的地址和没有转换的一样。然后再调用方法getB(),按照常规,它应该调用类型BaseB的方法,可是由于当前指向地址为BaseA*的起始地址,调用getB其实就是调用虚函数表中的第一个方法,而当前指向地址中虚函数表的第一个方法为BaseA的getA(),所以,两次调用得到结果都是22。具体地址参照截图:
BaseB* insB = ins;cout<<"c cast:\n\t(BaseA*)insB->getA():"<<((BaseA*)insB)->getA()<<endl; //33cout<<"c cast:\n\t(BaseB*)insB->getB():"<<((BaseB*)insB)->getB()<<endl; //33这里和刚才上面分析的一样,就不再赘述:直接看图:
cout<<"c cast:\n\t(BaseA*)insB->getMoreSpace():"<<((BaseA*)insB)->getMoreSpace()<<endl;
这里和上面讲述的道理一样,不过getMoreSpace()是第二个虚函数,所有会调用虚函数表中的第二项,而insB是BaseB指针类型,所有会调用BaseB中的第二个虚函数forA(),(说明:如果BaseB并没有第二虚函数,会导致运行时错误)见图:
使用动态转换dynamic_cast和先转子类再转父类的代码就不在详述了,注意:在使用dynamic_cast的时候,必须保证目标类是多态类,多态类后文有说明。
多态类:
参考:http://www.cnblogs.com/weidagang2046/archive/2010/04/10/1709226.html
多态类型在使用时需要注意:被转换对象obj的类型T1必须是多态类型,即T1必须公有继承自其它类,或者T1拥有虚函数(继承或自定义)。若T1为非多态类型,使用dynamic_cast会报编译错误。下面的例子说明了哪些类属于多态类型,哪些类不是://A为非多态类型 class A{};//B为多态类型class B{ public: virtual ~B(){}};//D为多态类型class D: public A{};//E为非多态类型class E : private A{};//F为多态类型class F : private B{}参考:http://www.cnblogs.com/weidagang2046/archive/2010/04/10/1709226.html
总结:
在进行交叉转换的时候,尽量使用C++类型安全的dynamic_cast。不过建议尽量少使用多继承,能单继承的就尽量简单化。
小弟不才,诸多错误,还望各位大神多多指教。
- C++多继承动态交叉转换dynamic_cast
- 关于多继承,dynamic_cast转换失败的问题
- dynamic_cast 动态强制类型转换
- dynamic_cast 与 避免 "向下转换" 继承层次
- static_cast,dynamic_cast,reinterpret_cast和c语言转换
- 0.c++-static_cast、reinterpret_cast、dynamic_cast、等转换
- c++ 类型转换(c cast static_cast dynamic_cast)
- C++类型转化分析:动态态转换->dynamic_cast
- C++动态转换类型static_cast,dynamic_cast,reinterpret_cast和const_cast探究
- C++dynamic_cast
- mysql交叉表,行列动态转换
- mysql交叉表,行列动态转换
- C++ dynamic_cast进行下行转换时,…
- 【C++】强制类型转换(static_cast,reinterpret_cast,const_cast,dynamic_cast,explicit)
- [C++] 强制类型转换static_cast、dynamic_cast、reinterpret_cast和const_cast
- c++dynamic_cast、const_cast 、static_cast、reinterpret_cast强制类型转换
- C/C++学习(9)dynamic_cast<>强制转换
- static_cast与dynamic_cast转换
- 快速排序(算法)
- mysql查询的存取类型
- 字符串处理
- gridview中动态绑定lingkbutton
- How do I install GCC via Homebrew?
- C++多继承动态交叉转换dynamic_cast
- js基础
- oa 项目 权限树的js写法 老师写的(原件
- 2013/08/21 C# WPF 学习笔记
- java中采用SAX对XML文件解析
- java选择排序和冒泡排序
- Linux sendfile
- Hook :挂钩 NtResumeThread 实现全局Hook
- CPaintDC dc(this)中的this指针的含义解析