Search code examples
c++vtable

Is a vtable generated when a virtual function is immediately marked final?


In this post: Does final imply override?, one of the answers showed that you can declare a function virtual AND final in the same declaration. An example was given that this prevents derived classes from mistakenly declaring a function with the same signature, so as to avoid confusion about which function is actually being called.

My question is, will a compiler still generate a virtual table for such a function? I would use this technique more often if I knew I wasn't incurring the vtable runtime overhead.


Solution

  • Yes!

    Speaking practically...

    Firstly, virtual tables are not generated for functions; virtual tables are generated for types (with each instance having a pointer to the relevant virtual table).

    Eliding the entire virtual table for a type just because none of its function members can be further overridden would cause a wealth of problems; for example, the resulting binary still needs to be able to find that final type when the instance is referenced through a pointer-to-Base.

    The only time this may make sense is with a type with virtual members, which are all final, and no base:

    /**
     * No members override (as there's no base)
     * and no members may be overridden (as they're
     * all `final`).
     */
    struct Foo
    {
       virtual void foo() final {}
    };
    

    Does a compiler elide the virtual table then? Maybe. Probably not; why implement an alternative, special-case set of semantics for an extreme corner scenario?

    Actually, it would probably break anyway in the general case when you later add new virtual members further up the hierarchy:

    /**
     * Well, this one needs a virtual table...
     * ...and it's probably going to want to
     * point out where Foo::foo() is...?
     */
    struct Bar : Foo
    {
       virtual void bar() {}
    };
    

    Speaking legally...

    Besides all this, I can't see any evidence that eliding the virtual table would be ABI-compliant, at least not under Itanium:

    Each class that has virtual member functions or virtual bases has an associated set of virtual tables.

    The final specifier is a C++ construct only with no ABI support, prohibiting such magic.

    Speaking verifiably...

    Ultimately, though, the only way to be sure is to actually examine the code that your compiler produces.