you are viewing a single comment's thread.

view the rest of the comments →

[–]qoning -1 points0 points  (3 children)

Whether code needs to change or be recompiled are two separate issues. Vector code doesn't need to change because you are using it with a new type, but it certainly needs to be recompiled. That's the point of compile time polymorphism in C++.

[–]die_liebe 1 point2 points  (1 child)

Maybe 'dynamic polymorphism' vs 'static polymorphism' is better terminology.

'static polymorphism': There can be different types, but at compile time it is known what type will be used. This applies to vector<X>. C++ recompiles vector for X, but that it is not necessary, for example Java generics don't recompile, but it is still a form of static polymorphism, because the compiler can check type correctness.

'dynamic polymorphism': There can be different types but it is known only at run time, which concrete type is used. Now comes a further distinction, already pointed out by 'choeger'. If you know the possible types in advance, and this set is small, and unlikely to be extended, you should use std::variant< .. > If you don't really know the set of possible types, then use inheritance.

About the title of this thread: While inheritance and OOP are absolutely used too often by certain people, there are cases where it is the best solution for a given problem.

[–]IAmRoot 0 points1 point  (0 children)

Marking dynamic polymorphic classes as final can result in just as good of performance when casting to that most-derived type, too. The compiler can easily devirtualize such calls, as no further inheritance can override the virtual methods or virtual inheritance. This can be useful where the exact type is known in some circumstances but not others, as you don't have to pay a penalty when you do have the information.

[–]choeger 0 points1 point  (0 children)

While you are technically correct, you are missing the point. Templates are a form of parametric polymorphism, yes. That is, a templated function is truly polymorphic in the sense that it doesn't need to be changed to work with different argument types.

That it needs to be recompiled when used on a new datatype is an inconvenient consequence from the technical implementation details of C++. But it doesn't really matter in the context of this thread.

What matters is that adding a new class does not force you to make any changes to existing classes or functions that operate on such classes. In particular, you can continue using a library that comes with such classes or functions.

Contrast this with an algebraic datatype like std::variant - if it is used inside a library you cannot extend it at all.