Search code examples
c++inheritancevirtual

Virtual keyword makes inaccessible a method from the derived objects


I have this code:

#include <iostream>

class Super{
public:
    virtual void showName();
};

class Special1 : public Super {
public:
    void showName();
    void sayHello();
};

class Special2 : public Super {
public:
    void showName();
    void sayGoodbye();
};

void Super::showName() {
    std::cout << "I'm super!" << std::endl;
}

void Special1::showName() {
    std::cout << "I'm special1" << std::endl;
}

void Special1::sayHello() {
    std::cout << "Hello" << std::endl;
}

void Special2::showName() {
    std::cout << "I'm special2" << std::endl;
}

void Special2::sayGoodbye() {
    std::cout << "Goodbye" << std::endl;
}

int main () {
    Super *oSpec=new Super;

    Special1 *o1=static_cast<Special1 *>(oSpec);
    Special2 *o2=static_cast<Special2 *>(oSpec);

    oSpec->showName();
    o1->showName();
    o2->showName();

    o1->sayHello();
    o2->sayGoodbye();

    delete oSpec;

    return 0;
}

When I run it, it shows this output:

I'm super!
I'm super!
I'm super!
Hello
Goodbye

But, if I remove the virtual keyword from the declaration of the Super class:

class Super{
public:
    /*virtual*/ void showName();
};

The output becomes the correct one:

I'm super!
I'm special1
I'm special2
Hello
Goodbye

Then, my question is, why the presence of the virtual keyword makes the pointers o1 and o2 run the method Super::showName() instead of Special1::showName() or Special2::showName()?


Solution

  • The output is closer to correct with virtual and incorrect with it (unless you really wanted that). The cast doesn't change the type of the objects, just the type of the pointers. They are still of type Super, and so it's Super::showName that should run.

    Casting one pointer type to another pointer type doesn't change the type of the thing pointed to. How could it? The whole point of virtual functions is to be able to call methods on 'generic' pointers and get the correct derived class method.

    The classic example of why you use virtual functions is for musicians. You might have a function that causes the entire orchestra to play by calling the Play method on every Musician * it gets passed. For a Pianist, that has to call Pianist::Play.

    Normally, the compiler figures out which function to call at compile time -- early binding. The only information the compiler is sure to know is the type of the pointer. The virtual keyword causes the binding to occur late, at run time, when the actual type of the class member is known.

    By the way, you can still call the base class method, by using a scope override. For example o1->Super::showName();.

    In fact, the result you claim is 'correct' is catastrophic. Running Special1::showName() with the this pointer pointing to an object that is not of type Special1 (or something derived from it) is undefined behavior and can easily lead to a crash.