Search code examples
c++overridingvirtual-functionsmember-functionsshadowing

Why is a call to a shadowing non-virtual member function in the derived class not calling the base class member function?


Let's assume this scenario in Visual C++ 2010:

#include <iostream>

using namespace std;

struct Base {
    void Display() {
        cout << "Base: Non-virtual display." << endl;
    };
    virtual void vDisplay() {
        cout << "Base: Virtual display." << endl;
    };
};

struct Derived : Base {
    void Display() {
        cout << "Derived: Non-virtual display." << endl;
    };
    virtual void vDisplay() {
        cout << "Derived: Virtual display." << endl;
    };
};

int main() {
    Base ba;
    Derived de;

    ba.Display();
    ba.vDisplay();
    de.Display();
    de.vDisplay();
};

Theoretically, the output of this little application should be:

Base: Non-virtual display.
Base: Virtual display.
Base: Non-virtual display.
Derived: Virtual display.

because the Display method of the Base class is not a virtual method so the Derived class should not be able to override it. Right?

The problem is that when I run the application, it prints this:

Base: Non-virtual display.
Base: Virtual display.
Derived: Non-virtual display.
Derived: Virtual display.

So either I don't understand the concept of virtual methods or something strange happens in Visual C++.

What is the explanation?


Solution

  • Yep, you are misunderstanding a little.

    The method of the same name on the derived class will hide the parent method in this case. You would imagine that if this weren't the case, trying to create a method with the same name as a base class non-virtual method should throw an error. It is allowed and it's not a problem - and if you call the method directly as you have done it will be called fine.

    But, being non-virtual, C++ method lookup mechanisms that allow for polymorphism won't be used. So for example if you created an instance of your derived class but called your 'Display' method via a pointer to the base class, the base's method will be called, whereas for 'vDisplay' the derived method would be called.

    For example, try adding these lines:

    Base *b = &ba;
    b->Display();
    b->vDisplay();
    b = &de;
    b->Display();
    b->vDisplay();
    

    ...and observe the output as expected:

    Base: Non-virtual display.
    Base: Virtual display.
    Base: Non-virtual display.
    Derived: Virtual display.