12.2a — The override and final specifiers, and covariant return types

To address some common challenges with inheritance, C++11 added two special identifiers to C++: override and final. Note that these identifiers are not considered keywords -- they are normal identifiers that have special meaning in certain contexts.

Although final isn’t used very much, override is a fantastic addition that you should use regularly. In this lesson, we’ll take a look at both, as well as one exception to the rule that virtual function override return types must match.

The override specifier

As we mentioned in the previous lesson, a derived class virtual function is only considered an override if its signature and return types match exactly. That can lead to inadvertent issues, where a function that was intended to be an override actually isn’t.

Consider the following example:

Because rBase is an A reference to a B object, the intention here is to use virtual functions to access B::getName1() and B::getName2(). However, because B::getName1() takes a different parameter (a short int instead of an int), it’s not considered an override of A::getName1(). More insidiously, because B::getName2() is const and A::getName2() isn’t, B::getName2() isn’t considered an override of A::getName2().

Consequently, this program prints:


In this particular case, because A and B just print their names, it’s fairly easy to see that we messed up our overrides, and that the wrong virtual function is being called. However, in a more complicated program, where the functions have behaviors or return values that aren’t printed, such issues can be very difficult to debug.

To help address the issue of functions that are meant to be overrides but aren’t, C++11 introduced the override specifier. Override can be applied to any override function by placing the specifier in the same place const would go. If the function does not override a base class function, the compiler will flag the function as an error.

The above program produces two compile errors: one for B::getName1(), and one for B::getName2(), because neither override a prior function. B::getName3() does override A::getName3(), so no error is produced for that line.

There is no performance penalty for using the override specifier, and it helps avoid inadvertent errors. Consequently, we highly recommend using it for every virtual function override you write to ensure you’ve actually overridden the function you think you have.

Rule: Apply the override specifier to every intended override function you write.

The final specifier

There may be cases where you don’t want someone to be able to override a virtual function, or inherit from a class. The final specifier can be used to tell the compiler to enforce this. If the user tries to override a function or class that has been specified as final, the compiler will give a compile error.

In the case where we want to restrict the user from overriding a function, the final specifier is used in the same place the override specifier is, like so:

In the above code, B::getName() overrides A::getName(), which is fine. But B::getName() has the final specifier, which means that any further overrides of that function should be considered an error. And indeed, C::getName() tries to override B::getName() (the override specifier here isn’t relevant, it’s just there for good practice), so the compiler will give a compile error.

In the case where we want to prevent inheriting from a class, the final specifier is applied after the class name:

In the above example, class B is declared final. Thus, when C tries to inherit from B, the compiler will give a compile error.

Covariant return types

There is one special case in which a derived class virtual function override can have a different return type than the base class and still be considered a matching override. If the return type of a virtual function is a pointer or a reference to a class, override functions can return a pointer or a reference to a derived class. These are called covariant return types. Here is an example:

This prints:

called Derived::getThis()
returned a Derived
called Derived::getThis()
returned a Base

Note that some older compilers (e.g. Visual Studio 6) do not support covariant return types.

One interesting note about covariant return types: C++ can’t dynamically select types, so you’ll always get the type that matches the base version of the function being called.

In the above example, we first call d.getThis(). Since d is a Derived, this calls Derived::getThis(), which returns a Derived*. This Derived* is then used to call non-virtual function Derived::printType().
Now the interesting case. We then call b->getThis(). Variable b is a Base pointer to a Derived object. Base::getThis() is virtual function, so this calls Derived::getThis(). Although Derived::getThis() returns a Derived*, because base version of the function returns a Base*, the returned Derived* is downcast to a Base*. And thus, Base::printType() is called.

In other words, in the above example, you only get a Derived* if you call getThis() with an object that is typed as a Derived object in the first place.

12.3 -- Virtual destructors, virtual assignment, and overriding virtualization
12.2 -- Virtual functions and polymorphism

28 comments to 12.2a — The override and final specifiers, and covariant return types

  • Nitin

    I think covariant return types feature might be one of the uglier features of C++. In the given example:

    This results in a call to the function in the derived class but a return of a pointer to the base object! That is just so non-intuitive, wouldn't you agree? Bugs in programs making use of this feature will be a nightmare to track down 🙂

    • Alex

      I don't think it's quite as bad as you're imagining. Pointers or references to base classes are common in C++ and with virtual function resolution will resolve to derived class functions anyway. Without covariant return types, any derived override functions would need to return a base class pointer/reference.

      With covariant return types, you essentially get the same result, but with the added benefit of being able to get a pointer/reference to the derived type if the function is called with a derived object instead of a base. So it's slightly more useful if you need the functionality, and not harmful if you don't.

  • SandeepD

    In the text below the last code, there is a type - "Since d is a Derived, this calls Derived::getBase(), which returns a Derived*. "
    getBase() should be getThis()
    Surprisingly nobody noticed 🙂

    • Alex

      Thanks for the fix. This code sample was added to the site fairly recently, so it hasn't had as many readers as other parts of the site. Thanks for pointing out the error!

  • Luhan

    Would you know how to explain what is exactly a dynamic select type? I found this [] but I don't know if is it.

    • Alex

      I don't know what a "dynamic select type" is. Dynamic dispatch is a generic name for virtual function resolution.

      • Luhan

        I've already found the answer, you previously had commented it, just for the sake of clarity, I was referring to this part

  • AMG

    I've found an interesting topic "Function overload vs override". At this point you covered operator overload, function override, and I don't remember you discussed a function overload. Could you please address "function overload"? Thank you very much.

  • Tushar

    "One interesting note about covariant return types: In the above example, if you call getThis() with a Base (even if the Base is a pointer or a reference to a Derived), the object being returned will still be a Base*. This is because C++ can’t dynamically select types, so you’ll always get the type that matches the most base version of the function being called.

    You’ll only get a Derived* if you call getThis() with an object that is already a Derived."
    - I cannot understand what you have said here 🙁
    Please give some examples

    • Alex

      Basically, if you call getThis() with a Base reference or pointer, you'll always get a Base reference or pointer in return. This may seem counterintuitive, because if the Base pointer is pointing to a Derived object, you'd expect for it to call Derived::GetThis(), which returns a Derived pointer.

      So the only time you'll get a Derived pointer return result is if you call d->getThis() or d.getthis(), where d is a Derived object.

  • Omri

    "Note that these identifiers are not considered keywords -- they are normal identifiers that have special meaning in certain contexts."
    How can identifiers, that are a part of the language, not be considered key words?
    Does this mean, for example, that I can define a variable named final or overload and this will work?
    Are there more such identifiers that are not keywords?

    • Alex

      > Does this mean, for example, that I can define a variable named final or overload and this will work?

      Yes, that is exactly what it means. There are no other such identifiers at this time. But it's possible new ones could be added in future iterations of C++.

  • Hardik


    This Prints "I AM BASE" but as per the function getThis() It should return a ptr/reference to derived class which in turn, should have printed "I AM DERIVED".
    Is it like that Because (this) return the object being pointed to and here, that object is base, due to which it prints "I AM BASE" and also, Derived* just tells that the return type should be a matching to Derived class and since, base matches it, there's no error too !
    Help Please !
    Thanks In Advance ! 🙂

    • Alex

      Although you might think base.getThis() would return a Derived* since base is a reference to a Derived, in this case even though the Derived::getThis() is called, a Base* is returned. Then, because getDerived() is non-virtual, the Base version of getDerived() is called.

      A Derived* is only returned if the object calling getThis() is actually a Derived. If you're calling getThis() from a Base object, you'll get a Base* because the Base version of getThis() returns a Base*.

      This limitation exists because C++ is not able to dynamically select types.

  • Sydney

    I'm a little confused as to the usefulness of the override specifier. In the example below we mention that two of the functions won't work as overrides with the command.

    Wouldn't it then just be enough to make sure all the override functions have the same signature and return type, with pointers to the Base and Derived classes as exceptions?

    • Alex

      The whole point of the override specifier is to help ensure that your overrides DO have the same signature and return type. It's very easy to think they are the same but overlook some minor detail that makes them different.

      I can't tell you how many hours I've wasted debugging code that didn't work, only to find out that my override had a minor difference (e.g. an added or missing const) so it was being treated as a separate function rather than an override of a base function.

      • Sydney

        I see. I was under the impression the override specifier was supposed to "override" the restrictions on what was an override function. It makes more sense though that it's meant to force the compiler to consider the function as an override, serving as a check in case you forget to make it one. Thanks.

  • Gajendra Gulgulia

    can you please tell once more what is the purpose of "const" keyword after the function parameter, line in your class B:public A example above?

    • Alex

      It means the member function is a const member function. Const member functions promise not to modify the value of member variables, and can only call other const member functions (or non-member functions).

      • luke

        It took me a moment to remember what the purpose of const was in that place too.

        A suggestion: a quick note / appendix on what const does in all its different possible positions would be really helpful as it can sometimes be confusing.

        I put together one myself that I use for reference:

        thanks for all the great tutorials!!

  • Prado

    Amazing tutorials!

Leave a Comment

Put all code inside code tags: [code]your code here[/code]