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. The override specifier 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 (or is applied to a non-virtual 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 upcast 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

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

  • Gabe

    Do you think it is also important to discuss Devirtualization? I was reading about it of how the final identifier can optimize virtual functions and for the compiler to decide at compile time which function to call.

  • salah

    I have a query about the conversion of Derived to Base in "getThis()" function. When b->getThis gets implemented the compiler set the returned type to "Base*", so any change of return type in Derived vitual function other then Base* would be considered a compiler error, but since Derived is a Base so the compiler cast it to Base, Am I right?

  • choofe

    In covariant example isn't it better we use 'override' specifier in line 16 as in "Rule: Apply the override specifier to every intended override function you write."
    Or there are rules about covariant?

    • koe

      Yes you should. As these tutorials go on, the amount of specifiers and keywords is piling up lol..

  • hugo

    Hey Alex & nascardriver,
    I'm wondering what will be a realistic use case for the covariant type feature in virtual functions?

    As we saw in the example:

    We really can't leverage this override

    since the the returned type will be upcasted to base class.

    • nascardriver

      I can't provide a real example, but I'm thinking of chained calls where one of the functions is non-virtual

      If `d` was a `Base*` or `someVirtualFunctionWithCovariantReturnType` returned a `Base*`, you'd have to cast the returned value before being able to call a function that's a member of `Derived` but not of `Base`.

  • Sergey

    Hi! The author wrote, "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".

    I am a little bit confusing, cause it turns out that "override" and "final" is not applicable when overriding normal member functions. The following program does not compile.

    Am I right, that "override" and "final" is only applicable to virtual functions? Thanks in advance!

  • cdecde57

    Hello! I think I understand everything here except the covariant return types fully. Pretty much what I see is that we have a base and a derived class. Because the derived one is a child of the base class we are able to return different types like instead of returning a base class we can do a derived one because it is a child / inherited traits from the main base like in the previous lessons being able to make an array of animals that consisted of dogs and cats.

    Please help me with covariant return types I don't know if I am completely wrong or anything and feedback would be great. Thanks!

    And thank you for the tutorials btw this is the ONLY place I have learned c++ so far and I have gone to a couple of other places just to see what they are teaching and you do everything way better, from the detail and clarity to the in-depth reasons behind why you do what you do.

    • Alex

      Yes, covariant return types allow virtual functions in derived classes to return a Derived* if the base version of the function returns a Base*. That's really it.

  • Hi Alex!

    The first sentence of this lesson will need adjustment when C++20 is released. I won't list the new special identifiers, as they might still change.
    I won't tell you about all changes, but this is one that's easy to miss so I thought I'd point it out.

  • Vir1oN

    "Note that these identifiers are not considered keywords -- they are normal identifiers that have special meaning in certain contexts."

    I caught myself here realizing I don`t understand the difference between keywords and identifiers (which are not just "names"). Did I miss something in your tutorials before? If not, could you please expain that difference?

    • An identifier is a sequence of text, with some restrictions as to how it can start or contain.
      A keyword is one of a bunch of selected identifiers (eg. auto, break, const) or a type name.
      Every keyword is an identifier, but not all identifiers are keywords (eg. variable names are identifiers but not keywords).

      • Anastasia

        Same here :/ I still don't quite understand the difference between a keyword and an identifier in this particular example (with 'final' and 'override'). According to this:  -- we can use lower and uppercase letters for identifiers for example, but writing 'oveRRide' instead of 'override' won't work (tested). It's possible though to use 'override' as a variable name, for example:

        worked for me. Is this the difference? Does it mean that this kind of identifiers is considered as keywords only in a specific context (eg. labelling a function or a class)?

        *it's also possible that it's just a compiler extension (using 'override' as a variable name). I compiled it with a simple 'clang++' with no flags (was testing it in Termux, on my phone).

        • `override` isn't a keyword, you're allowed to use it as an identifier for own stuff (I strongly recommend not doing it).
          Keywords can't be used for own identifiers.

          `override`, `final` (and 2 more since C++20) only get special treatment in a specific context. They're still not keywords then, keywords are defined by name.

          • Anastasia

            Still trying to figure it out... It's too abstract :/
            "Keywords are predefined, reserved words used in programming that have special meanings to the compiler. Keywords are part of the syntax and they cannot be used as an identifier." (
            Is that quote correct? If it is it seems that 'final' and 'override' are treated by the compiler as keywords (predefined (I can't change the spelling) words with a special meaning). Only the part about using them as identifiers (var.names) seems to be different then ...

            > keywords are defined by name
            I'm not sure I understand what that means... Can you say the same thing, but for dummies? (a link to where I can read about that would do too). Thanks!

            • > Is that quote correct?
              "Predefined" and "defined by name" means that there's a list in the standard listing all keywords by name. It's not "if X has these properties, then it's a keyword", but only the words that are in the list are keywords. No matter where a keyword occurs (except in attributes (not covered on learncpp)), it's treated as a keyword, ie. you can't use it for anything else.

              Identifiers with special meaning (final etc.) are also predefined, but they're only _special_ in certain situation. N3151 ( ) discussed whether or not these identifiers should be keywords or not (They were added in C++11). The main reason appears to be to danger of breaking existing code. "final" and "override" are identifiers that are very likely to have been used by coders. Using these identifiers for keywords would break their code. Then again, C++20 will add "concept" as a keyword, which I think is equally likely to break existing code.
              If you read through the proposals (Documents suggesting new language features) of "final", "override", "import" and "module", you might find a better reason why they aren't keywords.

              • Anastasia

                Ah, that's why it's so confusing! So "context-sensitive keywords" were chosen in the end? Honestly, how many codes would a normal keyword 'ovrdecl' ('Proposal', end of paper) break? I know nothing about real code, but I'd say less than there are (and will be) confused beginners with all those different kinds of keywords...

                Thank you, it was very informative and cleared things up for me!

  • Spixmaster

    The line above is a member function. I really cannot find a solution. What does the const mean before the return type?

  • ok i have a dumb question, why c++ did not use "override" in place of "virtual" seems redundant to use both ...
    also i don't understand covariant return type main purpose is to use a virtual function to either return a pointer/reference to derived class if used on a derived object directly and return a pointer/reference to base class if used through the base class or through a base class pointer/reference, is my understanding correct ?
    i know its not needed is there a way to up-cast the return to the derived class in the last case ?

    • Alex

      > why c++ did not use "override" in place of "virtual" seems redundant to use both ...

      Unsure. Probably for human readability (as it's easy to miss the override tag at the end of the function prototype).

      Re: covariant return types, I think your understanding is correct. Yes, you can downcast (from base to derived) using static_cast (if you already know the object is a derived) or dynamic_cast (if you want the compiler to help you check).

  • 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]