C++ 就速度而言,静态功能与虚拟功能

C++ 就速度而言,静态功能与虚拟功能,c++,static-methods,virtual-functions,C++,Static Methods,Virtual Functions,我有点麻烦。在规划我的程序时,我考虑了2个版本: 在带有附加参数的类中使用静态方法(指向类副本的指针) 使用虚拟方法(vtable) 什么更快?为什么? 编辑:我需要做下一个算法:数组应该存储指向不同类的方法的指针(它们满足不同的游戏对象),例如,方法Draw() 主要任务是存储和调用不同类的方法。在这一点上,您可能根本不应该考虑微观优化——专注于选择高效算法,并使代码清晰正确;然后确定任何阻碍it按要求执行的瓶颈。话虽如此,这里有一些想法在不太可能的情况下,你会发现虚拟调度成为一个问题 这两个

我有点麻烦。在规划我的程序时,我考虑了2个版本:

  • 在带有附加参数的类中使用静态方法(指向类副本的指针)
  • 使用虚拟方法(vtable)
  • 什么更快?为什么?


    编辑:我需要做下一个算法:数组应该存储指向不同类的方法的指针(它们满足不同的游戏对象),例如,方法Draw()


    主要任务是存储和调用不同类的方法。

    在这一点上,您可能根本不应该考虑微观优化——专注于选择高效算法,并使代码清晰正确;然后确定任何阻碍it按要求执行的瓶颈。话虽如此,这里有一些想法在不太可能的情况下,你会发现虚拟调度成为一个问题

    这两个函数是不等价的——第一个(如果我理解你的意思的话)是通过显式地向静态函数传递
    this
    类指针来模拟一个非虚函数,并且可能与非静态等价函数的速度一样快。它的行为与虚拟函数不同,因此如果需要虚拟分派,就不能使用它

    非虚拟函数(几乎可以肯定)会比虚拟函数快一点——它更有可能是内联的,如果不是内联的,它可以直接调用,而不是在运行时查找。因此,只有在需要虚拟分派时才将函数声明为虚拟


    在极端情况下,通过将函数指针存储在对象中而不是使用编译器生成的虚拟分派,您可能能够在虚拟函数上节省一定程度的间接寻址。如果您发现虚拟调度是一个严重的瓶颈,并且您无法明智地重新设计算法以避免它,那么您只能作为最后的手段来执行此操作。

    首先,虚拟函数和您建议的内容有不同之处 语义学。如果你需要不同的行为,因为你有不同的 对象的类型,那么您很可能做得比 编译器实现虚拟函数。如果你不需要 它,然后只是不声明函数为虚拟

    在您知道性能问题之前,不要担心它

    如果在使代码正常工作后,确实发现性能问题 虚拟函数调用(通常是因为编译器无法内联 函数,因此您失去了接下来的所有优化 内联),您可以及时避免虚拟功能成本,如果您 正确设计类。假设所讨论的函数是
    f()

    如果你这样做了,比如,你有一个紧密的循环 在同一对象上不断调用
    f()
    ,可以执行以下操作:

    void
    tightLoop( Base& object )
    {
        Derived& o = dynamic_cast<Derived&>( object );
        for ( /* ... */ ) {
            o.f();
        }
    }
    
    void
    tightLoop(基础和对象)
    {
    派生&o=动态_转换(对象);
    对于(/*…*/){
    o、 f();
    }
    }
    
    当然,如果这样做,
    tightLoop
    只能用对象调用
    实际上是衍生的

    使用设计中有意义的东西。不要试图模拟
    这个
    指针。当你的程序工作正常时,考虑速度(W.R.T.这个问题)。什么使你认为你可以比编译器供应商更好地实现虚拟方法调度?是什么让你认为虚拟方法分派的性能对你很重要?哇。这是我见过的最令人震惊的案件之一。虚拟方法是C++的核心。这是最微小的微优化,让它决定类模型是疯狂的。@WORLD\u DYNAMIC\u用户没有人质疑速度在某些情况下是重要的。您可能在ereOn的评论中遗漏了一点:编写代码、度量、优化。是什么让你认为是调度扼杀了你的表现?即使是这样,您认为通过更改分派(并将其与重写和维护成本进行比较)可以节省多少开销实际上调用高级函数(如
    Draw()
    )的开销不会对性能产生任何明显的影响,因为每个对象每帧只做一次,所以我需要做下一个算法:数组应该存储不同类的方法(它们满足不同的游戏对象),例如,方法Draw()。我找到了两种方法:静态函数和虚拟函数。在最后一点上,请注意,除非有大量类型,否则vtables将缓存在处理器中,额外的间接级别很可能会产生非常有限的效果,而且实际上很容易测量。我打赌对性能的影响低于1%(远低于函数执行任何实际工作时的影响)。好的,“vtables将缓存在处理器中,额外的间接级别很可能会产生非常有限的影响”,而不是我将使用“模拟”这个指针。谢谢:)“首先,虚拟函数和您提出的有不同的语义。”-为什么?例如,我们有两种类型:瓶子和门。我可以使用虚拟方法“Draw()”创建父类。在数组中,我添加了指向子类的1个副本的指针,子类重载了这个方法。我可以调用“((Parent*)ptr[I])->Draw()。这不取决于孩子的班级!
    void
    tightLoop( Base& object )
    {
        Derived& o = dynamic_cast<Derived&>( object );
        for ( /* ... */ ) {
            o.f();
        }
    }