[读书笔记] 深入探索C++对象模型-第七章-站在对象模型的尖端(下)

整理本系列笔记的最后一篇,关于运行时类型信息(RTTI)。

保证安全的向下转型

向下类型转换:是指由父类向子类的类型转换,由于父类信息少于子类,所以通常来说,没有特殊机制支持的话,这种转换是不安全的,要支持此机制的话,在空间和时间上都需要额外的负担:
1. 空间上,需要额外的空间存储类型信息,通常是一个指针,指向某个类型信息节点。
2. 时间上,需要额外的时间,已决定执行期的类型。
一种主流的策略是通过经由虚函数的声明来区别class,通过将指向类相关的运行时信息的指针存入虚函数表,会大大降低额外负担。

保证安全的动态转型

也就是dynamic_cast<>表现出来的行为:

  • 如果向下转型是安全的,则返回适当的转换类型。
  • 如果不安全,则返回空。

对于如下代码:

Base* pb = new Derived;
Derived* pd =  dynamic_cast<Derived*>(pb);

对于dynamic_cast<>, 其成本来自于:
1. Devired的一个类型描述器会被编译器产生出来。
2. b指向的类对象的类型描述器要在运行期通过虚表指针取得,像下面这样:

((type_info*)(pb->vptr[0]))->_type_descriptor;

两个类型描述器需要进行比较,可能会交给一个库函数,无论如何,这显然比static_cast<>要昂贵的多,但也安全得多。

引用并不是指针

当对于一个指针施以dynamic_cast<>时,可能产生两种结果:
1. 传回真正的地址,这表示在保证安全的前提下,转换成功了,这个对象的动态类型被确认了,一些与类型有关的操作现在可以施行于其上了。
2. 传回0,表示没有指向任何对象,表示无法安全转型。
第二点对于引而言,并不适用,因为,引用不可以指向空,引用是一有对象的别名,如果一个引用可以设为0,则表示0被隐式的转换为某种类型的临时对象,引用成为该临时对象的一个别名(alias)。
所以当dynamic_cast<>运算符施行于引用是,不能提供等同于指针情况的返回非空或者空,而是发生如下事情:
1. 如果可以安全转型,则与指针情况类似。
2. 如果引用并不是真正是某一种子类,由于不能传回0,所以抛出bad_cast异常。
例如:针对指针我可以这样定义一个转换处理函数:

simplify_conv_op(Base* pb)
{
    Derived* pd =  dynamic_cast<Derived*>(pb)
    if(pd)
    {
        //...process pd
    }
    else
    {
        //pd is null which means cast fails.
    }
}

而针对引用,则不能通过空与非空来判断:

simplify_conv_op_ref(const Base& b)
{
    try {
        Derived& d =  dynamic_cast<Derived&>(b)
        //...process d
    }
    catch (bad_cast)
    {
        //catch bad_cast exception which means cast fails.
    }
}

Typeid运算符

通过typeid可以通过一个引用提前判断类型信息,已决定是否进行动态类型转化:

simplify_conv_op_ref(const Base& b)
{
    if(typeid(b) == typeid(Derived))
    {
        Derived& d =  dynamic_cast<Derived&>(b)
        //...process d
    }
    else()
    {
    //...
    }
}

typeid运算符返回一个类型为type_info的常量引用(const reference),type_info类的可能的声明如下:

class type_info {
public:
    virtual ~type_info();
    bool operator==(const type_info&) const;
    bool operator!=(const type_info&) const;
    bool before(const type_info&) const;
    const char* name() const;//original class name
private:
    //prevent memberwise init and copy
    type_info(const type_info&);
    type_info& operator=(const type_info&);

    //data member
};

整个关于C++对象模型的笔记全部结束了,算上本篇总共19篇,林林总总也是不少内容,希望可以对同行们有所帮助,当然,重要的是给自己一个Back-up,以便之后restore之用。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值