Exceptional C++

【Exceptional C++(26)】类型转换

2018-01-30  本文已影响14人  downdemo
class A { ... };
class B : virtual A { ... };
struct C : A { ... };
struct D : B, C { ... };
A a1; B b1; C c1; D d1;
const A a2;
const A& ra1 = a1;
const A& ra2 = a2;
char c;
// 对下列C中的转型语句写成C++风格转型
void f() {
    A* pa; B* pb; C* pc;
    pa = (A*)&ra1;
    // const_cast<A*>(&ra1)
    pa = (A*)&a2;
    // 无法用C++风格转型表达
    pb = (B*)&c1;
    // reinterpret_cast<B*>(&c1)
    pc = (C*)&d1;
    // 在C中是错的,在C++中不需要转型,pc = &d1
}
// 评判下列转型
// 如果设计转型的类没有虚函数,下列所有dynamic_cast都是错的
// 所以我们假设所有类都有虚函数
void g() {
    unsigned char* puc = static_cast<unsigned char*>(&c);
    signed char* psc = static_cast<signed char*>(&c);
    // 这两条都应该使用reinterpret_cast
    // char、signed char和unsigned char是互不相同的类型
    // 尽管之间存在隐式转换,它们也是互不相关的
    // 所以指向它们的指针也是不相关的
    void* pv = static_cast<void*>(&b1);
    B* pb1 = static_cast<B*>(pv);
    // 第一句的转型是不必要的
    // 本来就有从一个对象指针到void*的隐式转换
    B* pb2 = static_cast<void*>(&b1);
    // 转型也是多余的,因为实参已经是B*
    A* pa1 = const_cast<A*>(&ra1);
    // 合法,但用转型去const是一种不好的风格
    // 通常用mutable完成
    A* pa2 = const_cast<A*>(&ra2);
    // 错误,用该指针对对象进行写操作会产生未定义行为
    // 因为a2是const对象
    B* pb3 = dynamic_cast<B*>(&c1);
    // 错误,将pb3设置为null
    // 因为c1 IS-NOT-A B
    A* pa3 = dynamic_cast<A*>)(&b1);
    // 错误,b1 IS-NOT-A A
    // 因为B不是public继承A,而是private
    B* pb4 = static<B*>(&d1);
    // 没必要,派生类到基类的指针转换可以隐式完成
    D* pd = static_cast<D*>(pb4);
    // 可能你认为这里需要dynamic_cast
    // 当目标已知时,向下转型(downcast)可以是静态的
    // 不过如果你错了,这个转型无法告知出现的问题
    pa1 = dynamic_cast<A*>(pb2);
    pa1 = dynamic_cast<A*>(pb4);
    // 这两句看起来很相似,但第一个错误第二个正确
    // 不能用dynamic_cast把一个指向B的指针转为指向A
    // 因为B是private而非public继承A的
    // 而D通过C将A作为间接基类
    C* pc1 = dynamic_cast<C*>(pb4);
    // 正确,同上
    C& rc1 = dynamic_cast<C&>(*pb2);
    // 错误,因为*pb2不真的就是一个C
    // dynamic_cast会抛出一个bad_cast异常报告失败
    // 因为dynamic_cast可以在指针转型失败时返回null
    // 但没有null reference,所以只能抛出一个bad_cast异常
}
上一篇下一篇

猜你喜欢

热点阅读