Home > Net >  Virtual C method with no polymorphism
Virtual C method with no polymorphism

Time:11-19

Suppose you have this simple class hierarchy:

struct base {

   virtual void f () const = 0;

};

struct derived : public base {

   virtual void f () const final
   {
      ...
   }   

};

There is only one implementation of f(), and because it is declared final, may we consider that there is no polymorphism ?

If so, will the compiler optimize code by avoiding use of a virtual table since 'You don't pay what you don't use ?'

Thank you.

CodePudding user response:

There is a polymorphism because there is a virtual function and you may define other derived classes from the base class.

From the C 17 Standard (13.3 Virtual functions)

1 [ Note: Virtual functions support dynamic binding and object-oriented programming. — end note ] A class that declares or inherits a virtual function is called a polymorphic class.

CodePudding user response:

will the compiler optimize code by avoiding use of a virtual table

If the compiler has a pDerived->f() then yes, this is what it typically will do because this is what final is designed for in the first place.

If it has a pBase->f(), then such optimisation is only possible if the compiler can prove that pBase points to a derived and not any other class derived from base. f being or not being declared final is irrelevant for this analysis. Note that derived classes can come from different translation units. The compiler normally only sees one translation unit at a time, so it needs some kind of data flow analysis to eliminate this possibility. Link-time optimisations do not really help here because additional modules can be loaded at run time, and the link time optimiser cannot see them.

CodePudding user response:

I made an example in compiler explorer: https://godbolt.org/z/exsx8dzra

The code:

struct base {

virtual int f () const = 0;

};

struct derived : public base {

virtual int f () const final { return 2; }

};

int returnf(const base& b)
{
    return b.f();
}

The Assembly (x86-64 gcc12.2, -std=c 20 -O3) :

main:
 xor    eax,eax
 ret    
 cs nop WORD PTR [rax rax*1 0x0]
 nop    DWORD PTR [rax]
returnf(base const&):
 mov    rax,QWORD PTR [rdi]
 mov    rax,QWORD PTR [rax]
 cmp    rax,0x401140
 jne    401138 <returnf(base const&) 0x18>
 mov    eax,0x2
 ret    
 nop    DWORD PTR [rax 0x0]
 jmp    rax
 nop    WORD PTR [rax rax*1 0x0]
derived::f() const:
 mov    eax,0x2
 ret    
 cs nop WORD PTR [rax rax*1 0x0]

Here you can see in the assembly that the virtual function call is not completely optimized away, namely there still is a check if the object is of the type derived:

 cmp    rax,0x401140
 jne    401138 <returnf(base const&) 0x18>

If so it returns the value specified in the method, otherwise it jumps to rax

  • Related