3

Let's say a virtual function is called on a derived class object (on the object normally or through pointer/reference) that overrides that function but none of its derived classes override it. Is it called "virtually" through v-pointer or as a normal function so all optimizations / inlining apply to it? Does the standard say anything about this?

class CBase{

public:
    virtual void doSomething() = 0;

};

class CDerived1 : public CBase{

public:
    void doSomething() override { /* do stuff */};

};

class CDerived2 : public CDerived1{


};

//...

CDerived1   derived1;
CDerived1*  p_derived1 = &derived1;

p_derived1->doSomething();
AdyAdy
  • 988
  • 6
  • 19
  • 1
    Please illustrate with some example code. Maybe so that the difference of the cases your are thinking of becomes visible. – Yunnosch Nov 17 '17 at 06:27
  • Virtual is virtual, inlining would require the compiler to be really really smart/aggressive and know the entire program. And you use derived twice? You mean derived from derived? The standard starts with virtual functions with "Virtual functions support dynamic binding and object-oriented programming." which is what happens after the compile ran. – Mihayl Nov 17 '17 at 06:30
  • [inline virtual function](https://stackoverflow.com/questions/2130226/inline-virtual-function) – Mihayl Nov 17 '17 at 06:36
  • @Yunnosch Edit done – AdyAdy Nov 17 '17 at 06:36

1 Answers1

4

Does the standard say anything about this?

No. Whether the call uses the dynamic dispatch mechanism or not is not observable behavior. And the standard only concerns itself with observable behavior.

How much compilers "devirtualize" virtual calls is ultimately implementation defined. If you just have T t; and you do t.whatever(), then you shouldn't use a compiler that cannot devirtualize that.

Inlining affects devirtualization as well. Given the T t declarations, if you pass a function a reference to this object, and it takes a T& parameter, calls into it can be devirtualized if that function gets inlined.

But if its a non-inlined instance of that function (say, a pointer to the function, perhaps through std::function or whatever), then devirtualization is much harder. See, the compiler doesn't see the whole program, so it cannot see if you have some class somewhere that inherits from T and overrides that method.

Only the linker, through whole program optimization, could possibly see all class definitions that inherit from it. And even then... maybe not. Because it is still technically possible for DLLs/SOs to inherit from classes. And the non-inlined function ought to be able to take those T&s and call their overridden methods.

So once you leave a chain of inlining where the object's dynamic type and virtual calls into it are both visible to the compiler, devirtualization becomes far more difficult if not impossible.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982