17.7 — Calling inherited functions and overriding behavior

By default, derived classes inherit all of the behaviors defined in a base class. In this lesson, we’ll examine in more detail how member functions are selected, as well as how we can leverage this to change behaviors in a derived class.

Calling a base class function

When a member function is called with a derived class object, the compiler first looks to see if that member exists in the derived class. If not, it begins walking up the inheritance chain and checking whether the member has been defined in any of the parent classes. It uses the first one it finds.

Consequently, take a look at the following example:

This prints

I am a Base
I am a Base

When derived.identify() is called, the compiler looks to see if function identify() has been defined in the Derived class. It hasn’t. Then it starts looking in the inherited classes (which in this case is Base). Base has defined an identify() function, so it uses that one. In other words, Base::identify() was used because Derived::identify() doesn’t exist.

This means that if the behavior provided by a base class is sufficient, we can simply use the base class behavior.

Redefining behaviors

However, if we had defined Derived::identify() in the Derived class, it would have been used instead.

This means that we can make functions work differently with our derived classes by redefining them in the derived class!

In our above example, it would be more accurate if derived.identify() printed “I am a Derived”. Let’s modify function identify() in the Derived class so it returns the correct response when we call function identify() with a Derived object.

To modify the way a function defined in a base class works in the derived class, simply redefine the function in the derived class.

Here’s the same example as above, using the new Derived::Identify() function:

I am a Base
I am a Derived

Note that when you redefine a function in the derived class, the derived function does not inherit the access specifier of the function with the same name in the base class. It uses whatever access specifier it is defined under in the derived class. Therefore, a function that is defined as private in the base class can be redefined as public in the derived class, or vice-versa!

Adding to existing functionality

Sometimes we don’t want to completely replace a base class function, but instead want to add additional functionality to it. In the above example, note that Derived::identify() completely hides Base::identify()! This may not be what we want. It is possible to have our derived function call the base version of the function of the same name (in order to reuse code) and then add additional functionality to it.

To have a derived function call a base function of the same name, simply do a normal function call, but prefix the function with the scope qualifier (the name of the base class and two colons). The following example redefines Derived::identify() so it first calls Base::identify() and then does its own additional stuff.

Now consider the following example:

I am a Base
I am a Base
I am a Derived

When derived.identify() is executed, it resolves to Derived::identify(). However, the first thing Derived::identify() does is call Base::identify(), which prints “I am a Base”. When Base::identify() returns, Derived::identify() continues executing and prints “I am a Derived”.

This should be pretty straightforward. Why do we need to use the scope resolution operator (::)? If we had defined Derived::identify() like this:

Calling function identify() without a scope resolution qualifier would default to the identify() in the current class, which would be Derived::identify(). This would cause Derived::identify() to call itself, which would lead to an infinite loop!

There’s one bit of trickiness that we can run into when trying to call friend functions in base classes, such as operator<<. Because friend functions of the base class aren’t actually part of the base class, using the scope resolution qualifier won’t work. Instead, we need a way to make our Derived class temporarily look like the Base class so that the right version of the function can be called.

Fortunately, that’s easy to do, using static_cast. Here’s an example:

Because a Derived is-a Base, we can static_cast our Derived object into a Base, so that the appropriate version of operator<< that uses a Base is called.

This prints:

In derived
In base

17.8 -- Hiding inherited functionality
17.6 -- Adding new functionality to a derived class

43 comments to 17.7 — Calling inherited functions and overriding behavior

  • Waldo Lemmer

    - {}:

    - &:

    - Should be const:

    - Should be const, GetValue() should be getValue()

  • J34NP3T3R

    does the static_cast example creates a copy of the class ?

    or since i see like a reference & does it permanently cast d into a class Base ?

  • Oleg Revedzhuk

    I’m curious, does the static cast for friend functionality just create a temporary base class object using the base values in derived as initializers, or is there some kind of special functionality that static casts have for derived classes?

    • nascardriver

      The `static_cast` created a temporary `Base` object. If `Base` had a user-defined copy-constructor, that would have been used. Since `Base` doesn't have one, a member-wise copy is made.

      The cast should have been `static_cast` to avoid copying anything. I've updated the lesson. This returned reference returns to the `Base` portion of the `Derived` without creating a new object.

  • maybe_Typo

    >>This means that we can make functions work differently with our derived classes by redefining them in the derived class!

    shouldn't with replaced with 'within'?

  • Ali Chowdhury

    How do I use these techniques in separate files?

  • saj

    Does calling member function of base class with scope resolution passes "this" pointer too through additional parameter? Because calling it with scope resolution seems similar to call to a static member function which doesn't have "this" pointer.

  • AbraxasKnister

    fails by telling me that void B::no_op() doesn't exist. I thought it did, since it was inherited from A.

    Just to be sure: do I need to expicitly declare B::no_op() in b.hpp to be able to define it in b.cpp? (side remark, real names of classes and member signatures differ). My guess:

    is how I'm supposed to do it.

    • nascardriver

      > is how I'm supposed to do it.
      That's how you're supposed to do it. I can't tell you why the explicit declaration is required, there must be a reason.

      • AbraxasKnister

        Symbols need to be declared before they're used (eg in a definition). For class members this is only possible during the class definition.

        The solution would be to have the declaration take place implicitly during the definition of derived classes. But if you then don't define B::no_op() you'll get a linker error instead of it using A::no_op().

        That means that at the time of definition of B::no_op() we need to go back and change the B class definition.

        I can see why they opted to not do that but it might come in handy, at least for pure virtual functions.

  • Abhay

    “The object of super class accesses the overridden member function of sub class”. Write a program to demonstrate this?

  • hellmet

    How do I make sure I'm not accidentally masking a method inside the parent of a class? Is making sure I don't the only way?

    Also, what happenes if I make a derived class a friend class of the base class, while also having the derived class inherit from the base class?


    I tried it, doesn't cause compile errors, I can access private variables of base from the derived. That's it I'm guessing?

  • Parsa

    If friend is not a member of the class, doesn't that mean the friend function shouldn't be able to access the class' private members?

  • in the section: "Redefining behaviors"

    i thought because we made it the opposite as private we can use the print from the base class as it can't find the print from the derived class

    • Hi Michael!

      Functions are resolved before their access modifiers are taken into account. Your compiler sees that you want to call derived.print, it finds @Derived::print, it stops searching. Only after this has happened, the compiler checks if you actually have access to @Derived::print, which you don't, so it errors out.

  • Dev

    I would like to ask you about polymorphism.

    Redefining behaviors - it's means: Creating functions, which overide function in base class.

    Could tell me if I create functions without virtual keyword, does it belong to polyformism?
    I know, that base ptr or ref, call only base functions (not dervied).

  • Pointer

    I have advanced a little more in the tutorial and now I think in the line

    we are doing upcasting and we are using anonymous sliced object to be able to use the friend function in the base class.

  • Ben


    "To modify a function the way a function defined in a base class works in the derived class, simply redefine the function in the derived class."

    I believe you meant:

    "To modify the way a function defined in a base class works in the derived class, simply redefine the function in the derived class."

  • Mohammad Abser Uddin abser

    why we use static cast?

  • Connor

    Hi Alex, I don't understand why we are using the 'using' keyword when redefining the access specifier on inherited members.

    why do we use 'using'. Also, why does c++ not include the braces when re-specifying access of a member function i.e.

    Thanks for the help :).

    • Alex

      In this context, the using keyword tells the code that we want to use the base class function at this new access level. C++ doesn't seem to like to create new keywords (that may cause naming conflicts with existing programs) so they often overload existing ones.

      I'm guessing the parenthesis are not needed because you don't need to respecify the parameters. Having empty parenthesis implies no parameters, which isn't necessarily the case.

  • Lokesh

    In the "Redefining functionality" section, I think this line needs review:
    "Therefore, a function that is defined as private in the base class can redefined as public in the derived class, or vice-versa!"
    A function that is defined as private in base class cannot be accessed by the derived class let alone redefining it.

  • Alex Silva

    Hi Alex

    Can I redefine a member variable in the derived class?

    • Alex

      I'm not sure what you mean by "redefine" in this context. You can't have a derived class change the type of a variable in the base class, but you can declare a member variable with the same name. This member variable will shadow the variable in the base class with the same name.

  • Sheena Chhabra

    It is written "Therefore, a function that is defined as private in the base class can redefined as public in the derived class, or vice-versa!"

    But the derived class can not access private members/functions of base class . so how is it possible ?

    • Alex

      If a function is private in the base class and reimplemented as public in the derived class, the derived version will be callable externally, but it won't be able to access private members from the base class (after all, they are private). There no rule-breaking here.

      • ASP

        Does that mean void print() in the base class and derived class are not the same functions?

        • Alex

          They are not the same. They just happen to share a name and the latter is considered an override of the former.

          • topherno

            Since derived functions like void print() are overrides of their base class counterparts, then why can't the override keyword be used with them? It looks like C++ compilers only allow the keyword to be used with virtual functions, yet it seems to me that derived override functions like void print() would equally benefit from it.

Leave a Comment

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