I have to make a decision regarding generalization vs polymorphism.
Well the scenario is standard: I want to make my monolithic interdependent code to be more modula
After having shoveled a little more experience on my plate, there are some things in templates that I don't like: There are certain disadvantages that disqualify template meta programming from being a useable language:
All that being said, I use it quite successfully on basic utilities and libraries. Writing high-level functionality or hardware related stuff with it, doesn't seem to cut it for me. Meaning I template my building blocks but build the house the classic way.
You're basically right, dynamic polymorphism (inheritance, virtuals) is generally the right choice when the type should be allowed to change at runtime (for example in plugin architectures). Static polymorphism (templates) is a better choice if the type should only change at compile-time.
The only potential downsides to templates are that 1) they generally have to be defined in the headers (which means more code gets #included), and this often leads to slower compile-times.
But design-wise, I can't see any problems in using templates when possible.
Which complies more with standard c++ style?
Depends on what "standard C++ style" is. The C++ standard library uses a bit of everything. The STL uses templates for everything, the slightly older IOStreams library uses inheritance and virtual functions, and the library functions inherited from C uses neither, of course.
These days, templates are by far the most popular choice though, and I'd have to say that is the most "standard" approach.
Properties of classic object-oriented polymorphism:
dynamic_cast
(and its potential to blow up into a customer's face) might easily compensate for thatProperties of compile-time polymorphism by template:
Note that there is no need to decide for either one. You can freely mix and mingle both of them (and many other idioms and paradigms). Often, this leads to very impressive (and expressive) code. (See, for example, things like type erasure.) To get an idea what's possible through clever mixing of paradigms, you might want to browse through Alexandrescu's "Modern C++ Design".
I use both in my large code base. When the type is known at compile time, I design it with templates, when it's known only at run time, I use virtual functions. I find the virtual functions easier to program and easier to read later, however there are times where performance is critical and the fact that the templated polymorphism (if you can really call it polymorphism) can be inlined really helps.
From my point of view it is what ever you are best at. If you have more experience with OO use OO. If you have more experience with generics use generics.
Both techniques have some equivalent patterns that mean for a lot of things you can use either. EG Strategy in OO vs Policy in Generics or Template Method in OO vs Commonly Recurring Template Pattern in Generics.
If you are planning refactor production code that already works but the structure is a bit smelly. Don't use it as an excuse to play with some new design technique, because in a year or two once you understand the technique better you may regret how you refactored your code. It is very easy to introduce a new inflexibilities when applying techniques as you are learning them. The aim of is to improve the design of existing code if you aren't skilled in a technique how do you know you are improving the design as opposed to building a large phallic symbol in your code.
Personally I am better at OO and tend to favour it as I know I can produce clean designs that are easy to understand and that most people can change. Most generic code I right is aimed at interfacing with other generic code, eg writing an iterator, or a generic function for algorithms.
It's something of a false opposition. Yes, the major use of inheritance and virtual functions is in iostreams
, which are very old, and are written in quite a different style to the rest of the std
libraries.
But many of the "coolest" modern C++ libraries such as boost do make use of runtime polymorphism, they just use templates to make it more convenient to use.
boost::any
and std::tr1::function
(formerly also from boost) are fine examples.
They are both single item containers to something whose concrete type is unknown at compile-time (this is especially obvious with any
, because it has its own kind of dynamic cast operator to get the value out).