对下面要记下的 dynamic_cast的盲点, 我都记不清是曾经掌握又忘记, 还是压根儿从来就不知道.
1 四个之中选择哪个
很多C++资源上对C++转型四大金刚: const_cast, dynamic_cast, reinterpret_cast, static_cast语焉不详, 在实际情况中, 想写一个C风格的转型的冲动之前, 停下来一思索, 才发现仅仅拥有More Effective C++中条款2标题的建议还是不够的: 最好使用C++转型操作符. 这个条款得看进去, 才能做好这个4选1的题目. 在大师Scott对这个条款的详细解释中, 并没有提及这样的一个事实: 对于给定的一个转型, 并非只有一个可行的转型操作符, 面对这种情况应该如何选择. 当然底限是只要选择一个可行的即可, 忽悠编译器放行.
2. dynamic_cast 一定得涉及两个类型?
VC2008的编译器输出中也这么说:
printf("%p, %p\n", b1, dynamic_cast(b1) );
error C2680: 'char *' : invalid target type for dynamic_cast
target type must be a pointer or reference to a defined class
dynamic_cast对 void *有特殊对待, 顺带地, 对const void *也有特殊对待, 是的, 还有const void *. 也就是说, 对下面的两个语句, 它是能够通过编译的:
printf("%p, %p\n", b1, dynamic_cast(b1) );
printf("%p, %p\n", b1, dynamic_cast(b1) );
不光是以上形式出乎我的意料, 语意上也是如此, 这么一个转型, 你可以获得b1 所涉指的那个对象的起始地址, 假设以下面形式继承:
B1 B2
\ /
\ /
D
D * d = new D();
对象只有一个, 但它可以化身作B1 或 B2, 或D 任何一个. 而以上形式的dynamic_cast可以在手握b1 或 b2的指针时仍然能够得到那个唯一的对象D的起始地址.
class B1 {
int m_b;
public:
virtual ~B1() { }
};
class B2 {
int m_b2;
public:
virtual ~B2() { }
};
class D : public B2, public B1 {
int m_d;
};
int main(int argc, char *argv)
{ D * d = new D();
printf("%p\n", d);
B1 * b1 = dynamic_cast<B1*>(d);
B2 * b2 = dynamic_cast<B2*>(d);
printf("%p, %p\n", b1, dynamic_cast<const void *>(b1) );
printf("%p, %p\n", b2, dynamic_cast<void*>(b2) );
return 0;
}
|
得到的结果:
003D4FC0
003D4FC8, 003D4FC0
003D4FC0, 003D4FC0
注意第二行中的不同.
3. 顺带地说, dynamic_cast在绝大多数情况下涉及两个运行时应该有关联的两个类型的指针或引用, 仍以上面代码为例, B1 和 B2 在编译期没继承关系, 但在运行期, 通过D的实例, dynamic_cast可以在它们之间作横向转型.
阅读(1868) | 评论(0) | 转发(0) |