Search

11.6a — 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 a function 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
7
11.6b -- Hiding inherited functionality
Index
11.6 -- Adding new functionality to a derived class

7 comments to 11.6a — Calling inherited functions and overriding behavior

  • 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

    @Alex
    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.

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter