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异常
}
网友评论