Overriding Functions

The C++03 way

In C++03, the virtual keyword is used to implement function overloading, as shown in the example below:

class Shape
{
public:
    virtual bool isCircle()
    {
        return false;
    }
};


class Circle : public Shape
{
    virtual bool isCircle()
    {
        return true;
    }
};

We can test this code as follows:

bool test()
{
    Shape* shape = new Circle();
    return shape->isCircle();
}

This will return true, demonstrating that the isCircle() method has been overridden as expected.

In this example, the virtual keyword has two purposes; it is used in the base class to signify that a function may be overridden, and again in the subclass to override the method.

After reviewing the above code, we may spot that isCircle() could be marked as a const method. So we might change the Shape class as follows:

class Shape
{
public:
    virtual bool isCircle() const
    {
        return false;
    }
};

The side-effect of this is that test() now returns false. This is because the two functions have a different signature. The version of isCircle() in the Circle class no longer matches function prototype in the base class.

To complete our refactoring, we must also use the const modifier in the Circle class:

class Circle : public Shape
{
    virtual bool isCircle() const
    {
        return true;
    }
};

The C++11 way

In C++11, we can be more explicit by using the new override and final keywords. By signalling our intentions more clearly, the compiler will be able to spot mistakes at compile time.

Our ‘shapes’ example can be written in C++11 as follows:

class Shape
{
public:
    virtual bool isCircle()
    {
        return false;
    }
};


class Circle : public Shape
{
    bool isCircle() override
    {
        return true;
    }
};

The compiler now knows that Circle::isCircle() is supposed to override the method in the base class. If it cannot find a corresponding function in Shape, it will report a compilation error.

The final keyword can be used in the same way as override, the difference being that any methods marked final cannot be overriden by any subclass of Circle. Also, an entire class can be marked as final, which prevents any class from being derived from it.

Using the override and final keywords is an excellent way to avoid pitfalls such as the one described above.