C++ 中是否有多态性的替代方案?

发布于 2024-07-14 12:38:29 字数 507 浏览 9 评论 0 原文

CRTP是在这个关于动态多态性的问题中提出的。 然而,据称这种模式仅对静态多态性有用。 我正在查看的设计似乎受到虚拟函数调用的速度阻碍,如 在这里暗示。 甚至 2.5 倍的加速都很棒。

所讨论的类很简单,可以完全内联编码,但是直到运行时才知道将使用哪些类。 此外,他们可能会以任何顺序被锁起来,使表现雪上加霜。

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

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

The CRTP is suggested in this question about dynamic polymorphism. However, this pattern is allegedly only useful for static polymorphism. The design I am looking at seems to be hampered speedwise by virtual function calls, as hinted at here. A speedup of even 2.5x would be fantastic.

The classes in question are simple and can be coded completely inline, however it is not known until runtime which classes will be used. Furthermore, they may be chained, in any order, heaping performance insult onto injury.

Any suggestions (including how the CRTP can be used in this case) welcome.

Edit: Googling turns up a mention of function templates. These look promising.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

一影成城 2024-07-21 12:38:29

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

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

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

与静态绑定调用相比,虚拟方法调用的性能开销非常小。 我强烈建议您查看这个SO问题的答案。

Polymorphism literally means multiple (poly) forms (morphs). In statically typed languages (such as C++) there are three types of polymorphism.

  1. Adhoc polymorphism: This is best seen in C++ as function and method overloading. The same function name will bind to different methods based on matching the compile time type of the parameters of the call to the function or method signature.
  2. Parametric polymorphism: In C++ this is templates and all the fun things you can do with it such as CRTP, specialization, partial specialization, meta-programming etc. Again this sort of polymorphism where the same template name can do different things based on the template parameters is a compile time polymorphism.
  3. Subtype Polymorphism: Finally this is what we think of when we hear the word polymorphism in C++. This is where derived classes override virtual functions to specialize behavior. The same type of pointer to a base class can have different behavior based on the concrete derived type it is pointing to. This is the way to get run time polymorphism in C++.

If it is not known until runtime which classes will be used, you must use Subtype Polymorphism which will involve virtual function calls.

Virtual method calls have a very small performance overhead over statically bound calls. I'd urge you to look at the answers to this SO question.

明媚殇 2024-07-21 12:38:29

我同意 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...
  }
}

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

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

I agree with m-sharp that you're not going to avoid runtime polymorphism.

If you value optimisation over elegance, try replacing say

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

with something like

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...
  }
}

it's not pretty, certainly not OOP (more a reversion to what you might do in good old 'C') but if the virtual methods are trivial enough you should get a function with no calls (subject to good enough compiler & optimisation options). A variant using dynamic_cast or typeid might be slightly more elegant/safe but beware that those features have their own overhead which is probably comparable to a virtual call anyway.

Where you'll most likely see an improvement from the above is if some classes methods are no-ops, and it saved you from calling them, or if the functions contain common loop-invariant code and the optimiser manages to hoist it out of the loop.

狼亦尘 2024-07-21 12:38:29

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

You can go the Ole C Route and use unions. Although that too can be messy.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文