Definition
The world of object-oriented programming revolves around explicit interfaces and runtime polymorphism. In the world of templates and generic programming, explicit interfaces and runtime polymorphism continue to exist, but they’re less important. Instead, implicit interfaces and compile-time polymorphism move to the fore.
Terms Definition
OOP Example:
class Widget {
public:
Widget( );
virtual ~Widget();
virtual std::size_t size() const;
virtual void normalize();
void swap(Widget& other);
...
};
void doProcessing(Widget& w) {
if (w.size() > 10 && w != someNastyWidget) {
Widget temp(w);
temp.normalize( );
temp.swap(w);
}
}
-
Explicit Interface: We can look up this interface in the source code (e.g., the .h file for Widget) to see exactly what it looks like.
-
Runtime Polymorphism : some of Widget’s member functions are virtual, w’s calls to those functions will exhibit runtime polymorphism: the specific function to call will be determined at runtime based on w’s dynamic type
Templates and generic programming example:
template<typename T> void doProcessing(T& w) {
if (w.size() > 10 && w != someNastyWidget) {
T temp(w);
temp.normalize( );
temp.swap(w);
}
}
- Implicit Interfaces: The interface that w must support is determined by the operations performed on w in the template. In this example, it appears that w’s type (T) must support the size, normalize, and swap member functions; copy construction (to create temp); and comparison for inequality (for comparison with someNastyWidget). The set of expressions that must be valid in order for the template to compile is the implicit interface that T must support. In other words, the operation that T must support for the template to compile is the implicit interface of T.
- Compile-time Polymorphism: Because instantiating function templates with different template parameters leads to different functions being called, this is known as compile-time polymorphism. In other words, the function that being called according to template parameters is determined in compile time therefore it is called compile-time polymorphism.
Difference
Compile time polymorphism vs. runtime polymorphism
The difference between runtime and compile-time polymorphism is similar to the difference between the process of determining which of a set of overloaded functions should be called (which takes place during compilation) and dynamic binding of virtual function calls (which takes place at runtime).
Explicit vs. implicit interfaces
An explicit interface typically consists of function signatures, i.e., function names, parameter types, return types, etc.
An implicit interface is quite different. It consists of valid expressions.
template<typename T> void doProcessing(T& w) {
if (w.size() > 10 && w != someNastyWidget) {
...
}
}
The implicit interface for T (w’s type) appears to have these constraints:
- It must offer a member function named size that returns an integral value.
- It must support an operator!= function that compares two objects of type T. (Here, we assume that someNastyWidget is of type T.)
Note: Neither of the above need to be satisfy because of the operator overloading.
For example, the size function do not need to return an integral value. All it needs to do is return an object of some type X such that there is an operator> that can be called with an object of type X and an int (because 10 is of type int).
In other word, as long as the expressions are valid (i.e. code can compile without error), it is up to the developer to interpret the design of the implicit interface.
The expressions themselves may look complicated, but the constraints they impose are generally straightforward.
For example, if (w.size() > 10 && w != someNastyWidget) ...
it’s hard to say much about the constraints on the functions size, oper- ator>, operator&&, or operator!=, but it’s easy to identify the constraint on the expression as a whole. The conditional part of an if statement must be a boolean expression.
Conclusion
Just as you can’t use an object in a way contradictory to the explicit interface its class offers (the code won’t compile), you can’t try to use an object in a template unless that object supports the implicit interface the template requires (again, the code won’t compile).
Things to Remember
- Both classes and templates support interfaces and polymorphism.
- For classes, interfaces are explicit and centered on function signatures. Polymorphism occurs at runtime through virtual functions.
- For template parameters, interfaces are implicit and based on valid expressions. Polymorphism occurs during compilation through tem- plate instantiation and function overloading resolution.