2
votes

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.

1

1 Answers

3
votes

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.