文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>常见错误45: dynamic_cast带来的多义性解析失败----读书笔记《c++ gotchas》...

常见错误45: dynamic_cast带来的多义性解析失败----读书笔记《c++ gotchas》...

时间:2010-08-13  来源:lzueclipse

问题:决定一个抽象的Screen对象是否为EntryScreen(继承自Screen),还是其他继承自Screen的类型。

你的第一个冲动可能是扩张所有Screen:

class Screen {

public:

    //…

    virtual bool isEntryScreen() const {

        return flase;

    }

};

class EntryScreen : public Screen {

public:

    bool isEntryScreen() const {

        return true;

    }

};

//…

Screen *getCurrent();

//…

if(getCurrent()->isEntryScreen())

//…

这种做法的问题在于赋予了查询Screen对象的动态类型一事以合法地位。

这就捅了马蜂窝,未来会有更多的此类问题出来:

class Screen {

public;

    //…

    virtual bool isEntryScreen() const {return false;}

    virtual bool isPricingScreen() const {return false;}

    virtual bol isSwapScreen() const {return false;}

    //没玩没了

};

显然,这么一个接口设计出来就是为了被下面这样用的:

//…

if(getCurrent()->isEntryScreen())

    //…

else if(getCurrent()->isPricingScreen())

    //…

else if(getCurrent()->isSwapScreen())

    //…

这时应该考虑dynamic_cast。

if(EntryScreen *es = dynamic_cast<EntryScreen *>(sp) ) {

    //做有关EntryScreen的操作

}

如果强制类型转换成功,es或是指向一个完整的EntryScreen对象,或是继承EntryScreen的对象中的EntryScreen子对象。

dynamic_cast进行强制类型转换可能由于以下四种原因的任何一种而失败,返回一个NULL pointer:

1)强制类型转换无法进行

如果sp根本不是

指向一个完整EntryScreen对象,

或指向继承自EntryScreen的某个继承类型对象的子对象的话,会失败

2)sp本身是空指针

3)把某个根本无法访问的基类作为强制类型转换的源类型或目的类型

4)强制类型转换多义性

类型转换的多义性在设计良好的继承谱系中不常见,但在结构和访问层级设计很差的继承谱系中却时时现身:

这是个多继承的继承谱系,假定A类型有虚函数,并且此处只是使用了public方式的继承,那么一个D对象含有

2个A类型的子对象。

D *dp = new D;

A *ap = dp;//多义性错误

ap = dynamic_cast<A*> dp;//多义性错误

B *bp = dynamic_cast<B *>dp;//正确

C *cp = dynamic_cast<C *>dp;//正确

如果两次A类型被用作基类时皆以虚继承方式进行,多义性问题也就不存在了。

把继承谱系弄得更复杂点,以重新引入多义性:

A *ap = new D;//无多义性

E *ep = dynamic_cast<E *> (ap);//多义性

只要再精确些:

E *ep = dynamic_cast<B *>(ap);//没问题

注:A*类型转换到B*类型,B*类型再转换到E*类型。最好还是用虚继承简化继承谱系。

讨论下dynamic_cast的精妙之处:

dynamic_cast不一定是动态的,因为它不一定做运行期校验。

使用dynamic_cast把一个派生类类型的指针(或引用)转换到它的以public方式继承的基类(此处说的是向上转型,

而不是向下转型),不用做运行期校验。

这种情况下,强制类型转换时不需要的。

如果把一个派生类类型的指针转换至void *指针,也不做运行期检查。可是仅仅得到了指针,有啥用处!?

相关阅读 更多 +
排行榜 更多 +
辰域智控app

辰域智控app

系统工具 下载
网医联盟app

网医联盟app

运动健身 下载
汇丰汇选App

汇丰汇选App

金融理财 下载