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.