繁体   English   中英

派生类调用时的虚函数性能?

[英]Virtual function performance when called by derived classes?

从编译时已知为派生类的类调用虚方法时是否存在性能损失? 下面我用派生类显式调用force_speak

码:

#include <iostream>
#include <array>
#include <memory>

class Base
{
public:
  virtual void speak()
  {
    std::cout << "base" << std::endl;
  }
};

class Derived1 : public Base
{
public:
  void speak()
  {
    std::cout << "derived 1" << std::endl;
  }
};

template<class B>
void force_speak(std::array<std::unique_ptr<B>, 3>& arr)
{
  for (auto& b: arr)
  {
    b->speak();
  }
}

int main()
{
  std::array<std::unique_ptr<Derived1>, 3> arr = 
    {
      std::unique_ptr<Derived1>(new Derived1),
      std::unique_ptr<Derived1>(new Derived1),
      std::unique_ptr<Derived1>(new Derived1)
    };
  force_speak(arr);
  return 0;
}

从编译时已知为派生类的类调用虚方法时是否存在性能损失? 见下面的代码。

这取决于。 大多数编译器会像这样“去虚拟化”代码:

Derived1 d;
d.speak();

对象的动态类型在调用站点是已知的,因此编译器可以避免通过vtable进行调用,并且可以直接调用Derived1::speak()

在您的示例中,编译器需要更智能,因为在force_speak您只有Derived1*指针(存储在unique_ptr对象中),并且在该上下文中,不清楚指向对象的动态类型是Derived1还是更多派生类型。 编译器要么需要force_speak的调用内联到main (动态类型已知的位置),要么使用一些关于类型的其他知识来允许虚拟化发生。 (作为附加知识的一个示例,整个程序优化可以确定在程序中的任何位置没有声明其他派生类型,因此Derived1* 必须指向Derived1 。)

使用C ++ 11 final关键字可以帮助编译器对某些情况进行虚拟化,例如,如果Derived1被标记为final那么编译器就知道Derived1*只能指向Derived1而不是指向它的某些其他类型可能会覆盖speak()

  1. 它依赖于编译器。 编译器必须静态地知道Derived1:speak()是唯一的选择。 这包括知道没有一些Derived2::speak()定义,其中class Derived2: public Derived1 但编译器可能根本不会实现这样的优化。

  2. 函数模板参数可以由编译器自动推导出来。 这是C ++标准的一部分。 编译器知道呼叫站点的参数类型,因此用户无需提供它。 注意,用户可以提供类型,并且例如可以提供类型兼容但与实际参数的类型不同的类型。

在这种特定情况下,答案可能是

如果编译器决定内联force_speak() ,理论上可以推断出数组中的所有指针都是Derived1实例,因此静态调用该方法。 (标准不需要此优化,因此无论是静态调用还是虚拟调用方法,都取决于您的特定编译器以及编译期间使用的选项。)

如果编译器没有内联调用,那么它必须发出虚拟调用方法的指令,因为你可以进一步派生类Derived1并再次覆盖该方法,将该类的实例存储在std::unique_ptr<Derived1> ,并传递进入函数的数组。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM