【问题标题】:Are there alternatives to polymorphism in C++?C++ 中是否有替代多态性的方法?
【发布时间】:2010-10-09 17:33:02
【问题描述】:

The CRTP 在这个关于动态多态性的问题中被建议。然而,据称这种模式只对静态多态有用。我正在查看的设计似乎在速度方面受到虚函数调用的阻碍,因为 hinted at here. 甚至 2.5 倍的加速都很棒。

所讨论的类很简单,可以完全内联编码,但是直到运行时才知道将使用哪些类。此外,他们可能以任何顺序被束缚,将性能侮辱堆积到伤害上。

欢迎提出任何建议(包括在这种情况下如何使用 CRTP)。

编辑:谷歌搜索出现了函数模板的提及。这些看起来很有希望。

【问题讨论】:

    标签: c++ virtual-functions


    【解决方案1】:

    多态性的字面意思是多种(多)形式(变形)。在静态类型语言(如 C++)中,存在三种类型的多态性。

    1. Adhoc 多态性:这在 C++ 中最好被视为函数和方法重载。相同的函数名称将根据调用的参数的编译时间类型与函数或方法签名的匹配来绑定到不同的方法。
    2. 参数多态性:在 C++ 中,这是模板以及您可以用它做的所有有趣的事情,例如 CRTP、专业化、部分专业化、元编程等。同样的这种多态性,相同的模板名称可以做不同的事情模板参数上是一个编译时多态性。
    3. 子类型多态性:最后,当我们听到 C++ 中的多态性这个词时,我们会想到这一点。这是派生类覆盖虚函数以专门化行为的地方。基于它指向的具体派生类型,相同类型的指向基类的指针可能具有不同的行为。这是在 C++ 中获得运行时多态性的方法。

    如果直到运行时才知道将使用哪些类,则必须使用涉及虚函数调用的子类型多态。

    与静态绑定调用相比,虚拟方法调用的性能开销非常小。我敦促你看看这个SO question.的答案

    【讨论】:

      【解决方案2】:

      我同意 m-sharp 的观点,即您不会避免运行时多态性。

      如果您更看重优化而不是优雅,请尝试替换说

      void invoke_trivial_on_all(const std::vector<Base*>& v)
      {
        for (int i=0;i<v.size();i++)
          v[i]->trivial_virtual_method();
      }
      

      类似的东西

      void invoke_trivial_on_all(const std::vector<Base*>& v)
      {
        for (int i=0;i<v.size();i++)
        {
          if (v[i]->tag==FooTag)
            static_cast<Foo*>(v[i])->Foo::trivial_virtual_method();
          else if (v[i]->tag==BarTag)
            static_cast<Bar*>(v[i])->Bar::trivial_virtual_method();
          else...
        }
      }
      

      它不是很漂亮,当然不是 OOP(更像是您在旧的“C”中可能会做的事情的回归)但是如果虚拟方法足够简单,您应该得到一个没有调用的函数(取决于足够好的编译器和优化选项)。使用 dynamic_cast 或 typeid 的变体可能更优雅/更安全,但要注意这些功能有其自身的开销,无论如何可能与虚拟调用相当。

      您最有可能从上面看到改进的地方是,如果某些类方法是无操作的,并且它使您免于调用它们,或者如果函数包含通用循环不变代码并且优化器设法提升它跳出循环。

      【讨论】:

      • 我相信模板中的 if 语句可能会让这个混乱变得更干净一些。无论如何看起来很有希望。
      • 请使用 static_cast 而不是 reinterpret_cast,后者在某些情况下会给出不正确的结果(在典型的实现中,如果 Foo 或 Bar 有多个基类而 Base 不是其中第一个)。
      • if-else 链很可能会变慢。分支机构相当昂贵。不仅如此,而且必须链接它们意味着您在时间关键部分具有 O(N) 行为......更好的比较是 switch 与虚函数调用。即使这样,速度也应该相似......
      【解决方案3】:

      您可以走 Ole C 路线并使用工会。虽然这也可能很混乱。

      【讨论】:

      • 我将这三个不同的时间读为“洋葱”,只能想象您的“混乱”工作流程涉及什么。
      猜你喜欢
      • 2010-09-20
      • 1970-01-01
      • 2021-01-30
      • 2011-04-21
      • 1970-01-01
      • 1970-01-01
      • 2021-11-06
      • 2023-03-21
      相关资源
      最近更新 更多