We're not supposed to reveal the inner secrets of C++. Otherwise you will find out that what's happening is simple and you will have no further use for us.
When you create an object in C++, all that's created are the data members. The class methods are functions and they reside in the code segment of the executable to which you have no access. That means all object use the same single set of methods.
In your animal/cat scenario, if you create a cat and pass it to a function expecting an animal
pointer or reference, and inside the function call the speak method, you will get the animal::speak() since the function argument is an animal pointer or reference. The cat-ness has been lost.
-
class animal
-
{
-
public:
-
void speak();
-
};
-
void animal::speak()
-
{
-
cout << "Generic noise" << endl;
-
}
-
class cat : public animal
-
{
-
public:
-
void speak();
-
};
-
void cat::speak()
-
{
-
cout << "Meow" << endl;
-
}
-
void TheTest(animal* a)
-
{
-
a->speak();
-
}
-
int main()
-
{
-
cat obj;
-
TheTest(&obj); //you see "Generic noise"
-
}
-
The next thing is to make the animal::speak() a virtual function. The code below is exactly the same as the code above with the exception that the animal::speak() method has been made virtual:
-
class animal
-
{
-
public:
-
virtual void speak();
-
};
-
void animal::speak()
-
{
-
cout << "Generic noise" << endl;
-
}
-
class cat : public animal
-
{
-
public:
-
void speak();
-
};
-
void cat::speak()
-
{
-
cout << "Meow" << endl;
-
}
-
void TheTest(animal* a)
-
{
-
a->speak();
-
}
-
int main()
-
{
-
cat obj;
-
TheTest(&obj); //you see "Meow"
-
}
-
What has happened here is that the virtual function causes the compiler to create a virtual function table (VTBL) that contains the addresses of the classe's virtual function's, whether inherited or overriden.
In your case the VTBL for cat contains the address of cat::speak(). You see, making the base class method virtual also makes the derived class method virtual. Finally, the address of the VTBL itself is put inside your cat object.
There is one VTBL for all cat objects.
Now when you are inside TheTest(animal* a), the compiler has generated code to access your object and get that VTBL pointer, then go to the VTBL and locate the cat::speak entry and then call that function by its address. And Presto! Meow.
Take the virtual out of the animal class, the VTBL is not created, and when you get to TheTest(anumal* a) no code is generated for a VTBL so all you get is animal::speak().
And that, is how object-oriented programming is implemented in C++: virtual functions.
Try doing a sizeof(cat). When the animal::speak()is not virtual, you get 1. When animal::speak() is virtual, you get 4. That 4 is enough memory to hold the address of that VTBL.