what is the difference between templates and polymorphism

10,749

Solution 1

You seem to misunderstand what polymorphism is.

Polymorphism, at its core, has nothing to do with derived classes. Polymorphism simply means the ability to use a type without knowing everything about it. Rather than using a concrete type, polymorphism relies on some form of prototype to define what types it takes. Any types that fit that prototype are accepted.

Runtime polymorphism, in C++, is provided by deriving classes from a base class that contains virtual functions. The base class and virtual functions form the polymorphic prototype. Code written to accept the base class that calls these virtual functions will accept any class instance derived from the base class.

Compile-time polymorphism is polymorphism that happens... at compile time ;) What this means is that the compiler must know what is going on. You may have written the C++ code against a polymorphic prototype, but the compiler doesn't care. You get specific concrete types post-compilation.

Compile-time polymorphism is provided by templates in C++. A template function or class can take any type which conforms to a prototype, usually called a "concept". Unlike base classes and virtual functions, the prototype is implicit: the prototype is defined only by how the type is used by the template function/class.

If you have this template function:

template<typename T>
void Stuff(T &t)
{
  t.call(15);
}

There is an implicit requirement on T. This requirement is that it has a member function called call. There must be a single overload of this member function which can be called with an integer value.

This means that any type that happens to fit this prototype can be used.

Template polymorphism is more broad than inheritance polymorphism, because it can be used by a broader array of types. A type has to be designed specifically to use inheritance polymorphism; you have to derive from a class. A type can be non-destructively (ie: you don't have to change the type itself) adapted to template polymorphism. Even moreso if your template prototype is well designed:

template<typename T>
void Stuff(T &t)
{
  call(t, 15);
}

All that this version of Stuff requires is that there is some function that takes a T& and an integer value. If I have some type that I want to use with Stuff, all I have to do is define a call function in an appropriate namespace (namely, the namespace that the type was defined in). And this will work just fine. All without modifying the type itself.

Of course, compile-time polymorphism is... compile-time. If I want some user input or data file to select the polymorphic type, templates aren't going to help a whole lot (though type erasure, a template-based technique, can help). The principle benefit of runtime polymorphism is that it is indeed runtime.

Another benefit is that it is more precise about its prototypes. Everything is explicitly stated about inheritance. The virtual function interface in a base class is clearly laid out. The compiler will stop you from attempting to use that base class incorrectly (calling methods that don't exist on it). Indeed, a decent IDE will guide your code so that you will only see the methods on the base class.

Template polymorphism is a lot more implicit. Since C++ has no way of spelling out the prototype that a particular template function/class puts on a type, it's very easy to accidentally call something on a template type that you shouldn't. The compiler will only detect this when you try to use a type that doesn't fit the prototype. And even then you will generally get a massive error spew (depending on how deeply nested your template code is) that makes it difficult to know where the problem is.

It's also a lot harder to implement the implicit template polymorphic prototype, since it isn't spelled out. Implementing a derived class requires walking through the base class, looking at all of the virtual functions, and implementing them. Doing this for a template prototype is much more difficult, unless there is documentation somewhere that spells it out. If you fail to implement something, you again get an error spew that is generally less than forthcoming about the problem.

Solution 2

In a nutshell, it comes down to the outcome of your commonality-and-variability analysis of the problem to be solved.

If you're doing the same operations on different stuff, then you would use templates e.g. List<int> and List<float>

If you're doing the same operations in different ways on the same stuff according to the context, which also has some commonality, then you would use polymorphism e.g. the AbstractInterface::openFile interface with the derivatives WindowsInterface::openFile and LinuxInterface::openFile, one of which would be used according to the context. The abstract interface identifies the commonality of the fact that the same operation is being done conceptually, the derivatives fulfil the variability of the implementation of the concept.

Share:
10,749

Related videos on Youtube

Naphstor
Author by

Naphstor

Software Development Manager with over 13 years of experience in Software Development Life cycle from concept through development and delivery of applications and custom solutions.

Updated on June 05, 2022

Comments

  • Naphstor
    Naphstor almost 2 years

    Hi all I have a doubt regarding templates and polymorphism. By definition polymorphism provides code reusability, and templates in some sense allows the user to use the same code by providing generic programming with different data types. So what is the benefit of using polymorphism over templates. It might be a silly questions but I am curious to know the exact difference.

    • Alok Save
      Alok Save almost 12 years
      Templates provide static/compile time polymorphism. While virtualism provides dynamic polymorphism.
    • Mooing Duck
      Mooing Duck almost 12 years
      What's different? Everything. Polymorphism is not even remotely about code reusability. Templates are.
    • Nicol Bolas
      Nicol Bolas almost 12 years
      @MooingDuck: Polymorphism does allow code re-use. Old code (written against a polymorphic base class) using new code (written towards the same base class).
    • ildjarn
      ildjarn almost 12 years
      @Nicol : I think his point is that polymorphism may allow code reuse, but that's not it's actual purpose.
  • Steve Jessop
    Steve Jessop almost 12 years
    "There must be a single overload of this member function which can be called with an integer value." -- and that call with int must not be ambiguous, and possibly some other condition that I've forgotten. That's why the polymorphic prototype is usually documented in terms of "this expression must have the following properties: ... ". If you try to document it in terms of which functions and overloads exist then you get into all sorts of edge cases.