Static polymorphism (first case) via CRTP is done at compile time and I would basically prefer it, if all classes are known at compile time. Note also that the Base
itself is not a class but a class template, so Base
is not a base class of Derived
.
It's not just performance but also a design decision of your project if should use first or second.
In the second case Base
is a base of Derived
with polymorphical behaviour, so for ex. method calls on derived can be called through a pointer to Base, for ex.:
Base* b = new Derived();
b->foo(); // calls Derived::foo via vtable lookup.
Depending how foo() is invoked, compiler can devirtualize it or not, for ex:
Base* b = new Derived();
b->foo(); // cannot be devirtualized
Derived* d = new Derived();
d->foo(); // probably can be devirtualized, because compiler knows
// via final that none can override foo,
// so it doesnt need to consult vtable.
Basically I prefere everything what can be done at compile time, not just because of performance, but also robustness - runtime errors are harder to handle. But it's also design decision - if the first method makes your project more complicated and small performance penalty doesn't matter, then you can go very well with second approach.
There is no "one fit's all" solution.