Tech News
← Back to articles

Devirtualization and Static Polymorphism

read original related products more articles

February 25, 2026

Devirtualization and Static Polymorphism

Ever wondered why your “clean” polymorphic design underperforms in benchmarks? Virtual dispatch enables polymorphism, but it comes with hidden overhead: pointer indirection, larger object layouts, and fewer inlining opportunities.

Compilers do their best to devirtualize these calls, but it isn’t always possible. On latency-sensitive paths, it’s beneficial to manually replace dynamic dispatch with static polymorphism, so calls are resolved at compile time and the abstraction has effectively zero runtime cost.

Virtual dispatch §

Runtime polymorphism occurs when a base interface exposes a virtual method that derived classes override. Calls made through a Base& are then dispatched to the appropriate override at runtime. Under the hood, a virtual table ( vtable ) is created for each class, and a pointer ( vptr ) to the vtable is added to each instance.

Figure 1: Virtual dispatch diagram. The method foo is declared virtual in Base and overridden in Derived . Both classes get a vtable , and each object gets a vptr pointing to the corresponding vtable .

On a virtual call, the compiler loads the vptr , selects the right slot in the vtable , and performs an indirect call through that function pointer. The drawback is that the extra vptr increases object size, and the indirection through the vtable makes the call hard to predict. This prevents inlining, increases branch mispredictions, and reduces cache efficiency.

The best way to observe this phenomenon is by inspecting the assembly1 code emitted by the compiler for a minimal example

class Base { public : auto foo () -> int ; }; auto bar ( Base * base ) -> int { return base -> foo () + 77 ; }

... continue reading