为什么使用typeid关键字设计不好?

时间:2012-03-03 15:46:15

标签: c++ typeid

我听过很多人说typeid的任何使用都是糟糕的设计,但对我而言似乎它提供了很好的实用性。

  1. 何时(和为什么)使用typeid“糟糕的设计”?
  2. 何时使用typeid可以接受?
  3. 当它不可接受时,你仍然需要类似的东西,那是什么 那会有一个好的设计吗?

3 个答案:

答案 0 :(得分:18)

问题不在于typeid。问题是看到typeid会鼓励你写这个:

PolymorphicType *pType = ...;
if(typeid(*pType) == typeid(Derived1))
  pType->Func1();
else if(typeid(*pType) == typeid(Derived2))
  pType->Func2();
else if(typeid(*pType) == typeid(Derived3))
  pType->Func3();

这就是我们所说的“非常愚蠢”。这是以尽可能最不合理的方式完成的虚函数调用。用于替换typeiddynamic_cast函数时,virtual可能会被滥用。

这个例子可能听起来很牵强。毕竟,很明显这只是一个虚拟电话。但是,糟糕的代码通常会从阻力最小的路径发展而来;所需要的只是一个人做typeid() == typeid(),这个代码的种子已经开始了。一般来说,如果你经常直接使用typeid,那么你正在采取其他语言结构可以做得更好的事情是非常好的。

typeid last 度假胜地的多态类型演绎方法。

typeid的所有使用是否都错了?当然不是。没有它,boost::any是不可能的。好吧,它可能可能,但它不会比void*更安全。 typeid是使类型安全boost::any类型擦除成为可能的原因。还有其他合法用途。

但是在代码行与使用比率方面,我建议它最多应该在10,000行代码中。比这少得多,你可能错了。

  

类型检查是否缓慢?

一般来说,调用typeid的主要原因是模板化代码(如boost::any)或者您期望多态类型。如果类型是静态确定的(即:给出了非多态类型的类型名称或值),那么您可以期望它在编译时完成。

这是你应该关注的多态值。我已经看到一个性能测试,它表明一些typeid实现实际上走了类层次结构,因此它们找到类型所花费的时间与实际类型和给定类型之间的类数成正比。每个实现都会有所不同,但这是一个很好的指示,也许你不应该把它放在性能关键的代码中。

答案 1 :(得分:6)

我认为没有人说使用typeid本身就是糟糕的设计;相反,你会听到的是typeid的使用指示糟糕的设计。这个想法是,任何区分(比如说)SquareCircle的逻辑实际上应该是 in 那些类,所以应该用虚函数(多态)表示。 / p>

毋庸置疑,这不是一个绝对的规则。

答案 2 :(得分:4)

那些给你这个好建议的人无法说出理由。这意味着他们是简单的cargo cult程序员。

所有表达式都具有静态编译时类型(模板扩展后)。所有类型都是多态的或不是。

我会试着详细说明为什么typeid(最接近的)在两种情况下都无用:

  1. 当表达式的静态类型不是多态时,没有理由使用typeid。编译器将使用静态类型,而不是动态类型,因此编译时函数重载起作用。使用模板化类型特征(例如is_same)可以更有效地检查类型标识。

  2. 如果表达式的静态类型是多态的,则typeid会失败。是的,它将提供有关对象动态类型的信息。但只有最衍生的动态类型。这违反了Liskov替换原则,因为给定类型BaseChild,添加从Grandchild派生的新类型Child将不会被视为Child。开放 - 封闭原则也被违反,因为在不重写所有内容的情况下,新设计无法扩展设计。没有封装,因为有关类层次结构的信息必须分散在整个程序中,从而产生强耦合。 dynamic_cast克服了一些但并非所有这些问题。

  3. 简而言之,使用typeid的程序将很难维护和测试。

    而且,与任何规则一样,可能存在有限的例外情况。您正在使用继承和虚函数的OO语言功能,但实际上并不需要多态设计。我可以想到一个:您希望使用type_info::name()将类型的名称记录为字符串。您也可以使用它来检测切片(已经违反了多态性)。但这仅适用于调试,绝不适用于控制程序流程。

相关问题