C++ Programming/Classes/Polymorphism

Dynamic polymorphism (Overrides)
So far, we have learned that we can add new data and functions to a class through inheritance. But what about if we want our derived class to inherit a method from the base class, but to have a different implementation for it? That is when we are talking about polymorphism, a fundamental concept in OOP programming.

As seen previously in the Programming Paradigms Section, Polymorphism is subdivided in two concepts static polymorphism and dynamic polymorphism. This section concentrates on dynamic polymorphism, which applies in C++ when a derived class overrides a function declared in a base class.

We implement this concept redefining the method in the derived class. However, we need to have some considerations when we do this, so now we must introduce the concepts of dynamic binding, static binding and virtual methods.

Suppose that we have two classes,  and. derives from  and redefines the implementation of a method   that resides in class. Now suppose that we have an object  of class. How should the instruction  be interpreted?

If  is declared in the stack (not declared as a pointer or a reference) the compiler applies static binding, this means it interprets (at compile time) that we refer to the implementation of   that resides in.

However, if we declare  as a pointer or a reference of class , the compiler could not know which method to call at compile time, because   can be of type   or. If this is resolved at run time, the method that resides in  will be called. This is called dynamic binding. If this is resolved at compile time, the method that resides in  will be called. This is again, static binding.

Virtual member functions
The virtual member functions is relatively simple, but often misunderstood. The concept is an essential part of designing a class hierarchy in regards to sub-classing classes as it determines the behavior of overridden methods in certain contexts.

Virtual member functions are class member functions, that can be overridden in any class derived from the one where they were declared. The member function body is then replaced with a new set of implementation in the derived class.

By placing the keyword virtual before a method declaration we are indicating that when the compiler has to decide between applying static binding or dynamic binding it will apply dynamic binding. Otherwise, static binding will be applied.

Again, this should be clearer with an example:

Our first calls to f and g on the two objects are straightforward. However things get interesting with our baz pointer which is a pointer to the Foo type.

f is not virtual and as such a call to f will always invoke the implementation associated with the pointer type—in this case the implementation from Foo.

Virtual function calls are computationally more expensive than regular function calls. Virtual functions use pointer indirection, invocation and will require a few extra instructions than normal member functions. They also require that the constructor of any class/structure containing virtual functions to initialize a table of pointers to its virtual member functions.

All this characteristics will signify a trade-off between performance and design. One should avoid preemptively declaring functions virtual without an existing structural need. Keep in mind that virtual functions that are only resolved at run-time cannot be inlined.

Pure virtual member function
There is one additional interesting possibility. Sometimes we don't want to provide an implementation of our function at all, but want to require people sub-classing our class to provide an implementation on their own. This is the case for pure virtuals.

To indicate a pure virtual function instead of an implementation we simply add an "<tt>= 0</tt>" after the function declaration.

Again—an example:

Because <tt>paint</tt> is a pure <tt>virtual</tt> function in the Widget <tt>class</tt> we are required to provide an implementation in all concrete subclasses. If we don't the compiler will give us an error at build time.

This is helpful for providing interfaces—things that we expect from all of the objects based on a certain hierarchy, but when we want to ignore the implementation details.

Let's take our example from above where we had a pure <tt>virtual</tt> for painting. There are a lot of cases where we want to be able to do things with widgets without worrying about what kind of widget it is. Painting is an easy example.
 * So why is this useful?

Imagine that we have something in our application that repaints widgets when they become active. It would just work with pointers to widgets—i.e. <tt>Widget *activeWidget const</tt> might be a possible function signature. So we might do something like:

We want to actually call the appropriate paint member function for the "real" widget type—not <tt>Widget::paint</tt> (which is a "pure" <tt>virtual</tt> and will cause the program to crash if called using virtual dispatch). By using a <tt>virtual</tt> function we insure that the member function implementation for our subclass -- <tt>Button::paint</tt> in this case—will be called.

Covariant return types
Covariant return types is the ability for a virtual function in a derived class to return a pointer or reference to an instance of itself if the version of the method in the base class does so. e.g.

This allows casting to be avoided.

virtual Constructors
There is a hierarchy of classes with base class <tt>Foo</tt>. Given an object <tt>bar</tt> belonging in the hierarchy, it is desired to be able to do the following:
 * 1) Create an object <tt>baz</tt> of the same class as <tt>bar</tt> (say, class <tt>Bar</tt>) initialized using the default constructor of the class. The syntax normally used is:
 * <tt>Bar* baz = bar.create;</tt>
 * 1) Create an object <tt>baz</tt> of the same class as <tt>bar</tt> which is a copy of <tt>bar</tt>. The syntax normally used is:
 * <tt>Bar* baz = bar.clone;</tt>

In the class <tt>Foo</tt>, the methods <tt>Foo::create</tt> and <tt>Foo::clone</tt> are declared as follows:

If <tt>Foo</tt> is to be used as an abstract class, the functions may be made pure virtual:

In order to support the creation of a default-initialized object, and the creation of a copy object, each class <tt>Bar</tt> in the hierarchy must have public default and copy constructors. The virtual constructors of <tt>Bar</tt> are defined as follows:

The above code uses covariant return types. If your compiler doesn't support <tt>Bar* Bar::create</tt>, use <tt>Foo* Bar::create</tt> instead, and similarly for <tt>clone</tt>.

While using these virtual constructors, you must manually deallocate the object created by calling <tt>delete baz;</tt>. This hassle could be avoided if a smart pointer (e.g. <tt>std::unique_ptr<Foo></tt>) is used in the return type instead of the plain old <tt>Foo*</tt>.

Remember that whether or not <tt>Foo</tt> uses dynamically allocated memory, you must define the destructor <tt>virtual ~Foo </tt> and make it <tt>virtual</tt> to take care of deallocation of objects using pointers to an ancestral type.

virtual Destructor
It is of special importance to remember to define a virtual destructor even if empty in any base class, since failing to do so will create problems with the default compiler generated destructor that will not be virtual.

A virtual destructor is not overridden when redefined in a derived class, the definitions to each destructor are cumulative and they start from the last derivate class toward the first base class.

Pure virtual Destructor
Every abstract class should contain the declaration of a pure virtual destructor.

Pure virtual destructors are a special case of pure virtual functions (meant to be overridden in a derived class). They must always be defined and that definition should always be empty.