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()?
The output is closer to correct with
virtualand 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 typeSuper, and so it’sSuper::showNamethat 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
Playmethod on everyMusician *it gets passed. For aPianist, that has to callPianist::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
virtualkeyword 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 thethispointer pointing to an object that is not of typeSpecial1(or something derived from it) is undefined behavior and can easily lead to a crash.