【问题标题】:dynamic_cast was introduced to C++ to ruin polymorphism? [duplicate]将 dynamic_cast 引入 C++ 以破坏多态性? [复制]
【发布时间】:2016-10-06 13:02:50
【问题描述】:

B. Stroustrup 最初将 C++ 设计为没有 dynamic_cast,但后来人们不得不在语言中添加一些东西。无论我在哪里遇到dynamic_cast 的用法,它都反对对象的多态使用。所以有时候你会更喜欢知道对象类型而不是尝试重新设计你的代码来利用多态性?那些是什么情况?能举个例子吗?

附:请考虑dynamic_cast 在代码中添加了大量 RTTI 信息,这是添加到语言的部分反射,因为类层次结构信息存储在编译代码中。这违背了 C++ 哲学——你为你使用的东西付费。 (我知道你可以关闭 RTTI,但默认情况下它是打开的,你可能在整个代码中都不需要它!)

编辑:根据@Griwes 的 cmets,RTTI 的转向是可能的,但它是未定义的行为。因此,上述与 C++ 哲学相关的结论变得更加有力。

【问题讨论】:

  • dynamic_cast 所需的“大量 RTTI 信息”已添加,因为 dynamic_cast 需要它。你为你使用的东西付费。最后一段没有意义。
  • 我认为这是一个“业务需求” :) 您需要有办法进行快速而肮脏的 hack。昨天的要求是持有大量Animal 对象并将它们全部设为sleep()。现在客户说让我们先拥有Cat 对象meow()。现在,什么更好?让Cat 总是在meow() 之前sleep() 或者只是拥有if (dynamic_cast<Cat*>(animals[i]) != NULL) ...? :) 你去。
  • “而不是试图重新设计你的代码来利用多态性” - 所以你是说在if (auto ptr = dynamic_cast<foo *>(bar)) 足够的所有情况下,我应该为我的类型添加一个新的虚函数?伟大的。 ...等一下。没有不烂的 C++ 开放式多方法。哎呀。
  • @R.MartinhoFernandes 我不确定——RTTI 不是语言的一部分,因此通常启用(包括开销),即使没有在特定程序中使用?我认为这就是 OP 的意思。
  • @PeterA.Schneider 语言中的一切“都是语言的一部分,因此通常启用”。这有点重复。然而,这并不意味着一切都必须生成代码。

标签: c++


【解决方案1】:

首先,RTTI 信息并不大。它包括代码的只读部分中的一些信息,以及虚拟表中的一个附加条目。从这个意义上说,异常的代价要高得多(实际上复制了一些生成的代码,除非抛出异常,否则 CPU 永远不会运行)。

C++ 的理念是,并且一直是,为您提供可以用来使您的代码更好的工具,但不能保护您免受这些工具的不当使用。如果你看到人们滥用动态转换,那太糟糕了,但 C++ 并不认为这是设计失败(不超过,比如说,多重继承)。

就个人而言,我喜欢仅将动态转换用作断言。换句话说,我构建了一个设计,其中我向下转换了一个类,并且我应该已经知道我要向下转换到什么类型。然后我使用动态转换来确保我的设计没有被破坏,而且我认为这确实是正确的类型。

这是必要的原因是因为您不能用返回不同返回类型的方法覆盖方法。如果你有 A,并且 B 和 C 从它继承,你不能让 A 包含:

class A {
...
   virtual A *some_method();
};

然后有:

class B : public A {
...
   override virtual B* some_method();
};

C++ 根本不允许这样做。由于这是不允许的,因此可能需要获取some_method 的返回值,并将其从A* 转换为B*。当你这样做时,最好确保你确实有一个 B 的实例,而不是,例如,C

【讨论】:

  • 重写返回子类型的方法是可以的。谷歌“返回协变类型的虚拟函数”。 override 关键字也应该放在函数声明的末尾。
猜你喜欢
  • 1970-01-01
  • 2015-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多