c++ dynamic_cast

转自:http://blog.csdn.net/passion_wu128/article/details/38511957

http://blog.csdn.net/bitboss/article/details/53574236

dynamic_cast
dynamic_cast的转换格式:dynamic_cast (expression)

将expression转换为type-id类型,type-id必须是类的指针、类的引用或者是void *;如果type-id是指针类型,那么expression也必须是一个指针;如果type-id是一个引用,那么expression也必须是一个引用。

dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。在多态类型之间的转换主要使用dynamic_cast,因为类型提供了运行时信息;

细说dynamic_cast
2.1 多态
多态这个真的是C++最难理解的内容之一了;我不敢保证我可以把多态讲清楚,但是这里又不得不提多态,dynamic_cast 只适用于含有虚函数的类之间的转换,所以,只取所需部分进行说明:

正如我们所知道的,多态的实现依赖于虚函数和继承(当然,这里是动态多态,这里不提静态多态,函数多态,宏多态之类的东西),更本质的说就是依赖于虚表指针,一般情况下,虚表指针(_vptr)都位于对象的首地址,指向一个虚表(_table),而虚表中的内容则是虚函数的地址;

利用一个接口多种实现实现多态,对应到软件工程里就是,一个变点,多个变体;有些扯远了;

好了,我们暂时只需要知道这些,因为danamic_cast需要用到这些;
(如果觉得自己忘掉了多态,那就去看书吧!!)

2.2 dynamic_cast实例解说

前面已经对dynamic_cast的概念进行了陈列,相信已经帮你回忆好了,那么,下面我们就要对dynamic_cast进行举例说明,更深一步去了解danamic_cast的实现原理!

我们都知道继承的机制是基类的指针(引用)可以指向派生类的指着或者(引用),反之则编译错误;
那么:

//现在我们有这样两个类
class Base
{
public:
    virtual void show(){}
};

class Derive:public Base
{
public:
    virtual void show(){}
};

//测试
情景一:

    Base* bptr = new Derive();
    //Derive* dptr = bptr;   //error
    Derive* dptr = dynamic_cast<Derive*>(bptr);  //没问题
    //dptr != NULL

情景二:

    Base* bptr = new Base();
    //Derive* dptr = bptr;  //error编译不过

    //编译可以过去,但是我们来看看dptr的值
    Derive* dptr = dynamic_cast<Derive*>(bptr);
    cout<<"dptr = "<<dptr<<endl; //dptr == 0000000;

2.2.1 从情景一进行分析

我们企图用一个基类的指针去赋值一个派生类的指针,注意,基类指针的初始化是用派生类对象指针初始化的,直接进行赋值的话,编译器会直接报错,但是通过dynamic_cast的强制转化就成功了,且dptr != NULL,这是为什么呢?

2.2.2 再从情景二分析

我们企图用一个基类的指针去赋值一个派生类的指针,注意,基类指针的初始化是用基类对象指针初始化的,直接进行赋值的话,编译器会直接报错,但是通过dynamic_cast的强制转化就成功了,但是dptr == NULL,这是为什么呢?

2.2.3 综合分析

其实,如果你仔细看dynamic_cast的定义的话,肯定明白,这就是dynamic_cast的本身的机制,(有兴趣的同学可以去尝试用static_cast测试一下,看看和dynamic_cast有什么不同)这就是dynamic_cast的奇特之处,它可以办到虚函数不能做到的事,而我先现在就是要去探索这个机制的实现原理,这就引出了本篇文章的重头戏RTTI(运行时类型检测的机制);

情景一,二再分析
情景一:
    Base* bptr = new Derive();
    //typeid(*bptr).name() 结果:class Derive
    cout<<typeid(*bptr).name()<<endl;

    //Derive* dptr = bptr;   //error
    Derive* dptr = dynamic_cast<Derive*>(bptr);  //没问题
    //typeid(*bptr).name() 结果:class Derive
    //dptr != NULL

情景二:

    Base* bptr = new Base();
    cout<<typeid(*bptr).name()<<endl; //结果:class Base;
    //Derive* dptr = bptr;  //error编译不过

    //编译可以过去,但是我们来看看dptr的值
    Derive* dptr = dynamic_cast<Derive*>(bptr);
    //cout<<typeid(*dptr).name()<<endl;  //程序会挂掉;
    cout<<"dptr = "<<dptr<<endl; //dptr == 0000000;

dynamic_cast 通过RTTI访问虚表里的type_info,再根据type_info和Deriver进行继承树的遍历判断是否有is-a关系,若有,则返回Deriver对象的引用或指针,否则返回NULL;

利用typeid可以得到对象的确切类型,注意typeid()里的参数是对象,是对dptr进行了解引用,如果是指针的话,返回的是指针的类型,得不到确切的结果的;


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值