type 与 RTTI

时常,我们在程序中经常出现这样的switch或者if-else分支:
if (pobj->IsKindOf(Circle))
else if (pobj->IsKindOf(Rectangle))
等。其中上面的IsKindOf也可能是我们自定义的GetType(),或者是C++标准中的dynamic_cast。

不管怎么样,这是十分不好的设计/风格。
原因很简单,要添加一个新的类型,所有这些条件判断的地方都需要做更改;反之,使用多态只需要添加一个SubClass(当然,也可以在类层次上作一些调整)。

关于RTTI, google是这么认为的:
运行时类型识别(Run-Time Type Information, RTTI) 我们禁止使用 RTTI。
定义:RTTI 允许程序员在运行时识别 C++类对象的类型。
优点:
RTTI 在某些单元测试中非常有用,如在进行工厂类测试时用于检验一个新建对象是否为期望的动态类型。
除测试外,极少用到。
缺点: 运行时识别类型意味著设计本身有问题, 如果你需要在运行期间确定一个对象的型类, 这通常说明你需要重新考虑你的类的设计。
结论:
除单元测试外, 不要使用RTTI, 如果你发现需要所写代码因对象类型不同而动作各异的话, 考虑换一种方式识别对象类型。
虚函数可以实现随子类类型不同而执行不同代码,工作都是交给对象本身去完成。
如果工作在对象之外的代码中完成,考虑双重分发方案,如Visitor 模式,可以方便的在对 象本身之外确定类的类型。
如果你认为上面的方法你掌握不了,可以使用RTTI,但务必请三思,不要去手工实现一个 貌似 RTTI 的方案(RTTI-like workaround),我们反对使用 RTTI,同样反对贴上类型 标签的貌似类继承的替代方案。

MFC的CObject::IsKindOf() 明确的指出Do not use this function extensively because it defeats the C++ polymorphism feature. Use virtual functions instead.

如何应对这个问题呢,
MartinFlower在《重构》中明确的指出了几条细则,包括:
Replace Type Code with Class;
Replace Type Code with State/Strategy;
Replace Type Code with Subclasses;
Replace Conditional with Polymorphism

既然如此,为什么还需要IsKindOf,dynamic_cast这些玩意呢。

在BS的《C++语言的设计与演化》中的《强制》一章“为什么提供一种危险‘特征’”一节中,我们可以找到讲RTTI作为标准的一些理由。这里就不一一罗列。

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.