简体   繁体   中英

Virtual function performance when called by derived classes?

Is there a performance penalty when a virtual method is called from a class that's known to be the derived class at compile time? Below I explicitly call force_speak with a derived class.

Code:

#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;
}

Is there a performance penalty when a virtual method is called from a class that's known to be the derived class at compile time? See code below.

It depends. Most compilers will "de-virtualize" code like this:

Derived1 d;
d.speak();

The dynamic type of the object is known at the call site, so the compiler can avoid going through the vtable to make the call and can just call Derived1::speak() directly.

In your example the compiler needs to be smarter because in force_speak you only have Derived1* pointers (stored inside the unique_ptr objects) and in that context it's not clear whether the dynamic type of the pointed-to objects is Derived1 or some more-derived type. The compiler either needs to inline the call to force_speak into main (where the dynamic type is known) or use some additional knowledge about the type to allow devirtualization to happen. (As one example of additional knowledge, whole program optimization can determine that there are no other derived types declared anywhere in the program, so a Derived1* must point to a Derived1 .)

Using the C++11 final keyword can help compilers to devirtualize some cases, eg if Derived1 is marked final then the compiler knows that a Derived1* can only point to a Derived1 and not some other type derived from it that might override speak()

  1. It's compiler dependent. Compiler must statically know that Derived1:speak() is the only option. That includes knowing that there is no some Derived2::speak() definition, where class Derived2: public Derived1 . But compiler might not implement such an optimization at all.

  2. Function template parameters can be deduced automatically by a compiler. This is part of C++ standard. Compiler knows the type of parameter at a call site so user does not have to provide it. Note, that user can provide the type, and thay can for example provide type compatible but different that the type of an actual parameter.

In this specific case, the answer is maybe .

If the compiler decides to inline force_speak() it could theoretically deduce that all of the pointers in the array are Derived1 instances and so call the method statically. (This optimization is not required by the standard, so whether the method is called statically or virtually depends on your particular compiler and possibly what options you use during compilation.)

If the compiler does not inline the call then it must emit instructions to call the method virtually, because you could further derive the class Derived1 and override the method yet again, store instances of that class in std::unique_ptr<Derived1> , and pass an array of those into the function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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