I was trying to understand virtual functions.
Consider the following code,
#include <iostream>
#include <memory>
#include <vector>
class Animal
{
public:
virtual void eat()
{
std::cout << "I eat like a generic animal.\n";
}
};
class Wolf : public Animal
{
public:
void eat()
{
std::cout << "I eat like a wolf!\n";
}
};
int main()
{
Animal a;
Wolf w;
a.eat();
w.eat();
}
With the virtual
keyword I get the output
I eat like a generic animal.
I eat like a wolf!
as it should.
But If I remove the virtual keyword I still get the same output! From my
elementary understanding of virtual functions, without the virtual
I should have got the output
I eat like a generic animal.
I eat like a generic animal.
Is there anything elementary here I am missing ?
I am using the g++ compiler on Linux
No, it's a right behavior. Virtual functions are needed to introduce polymorphism. To enable polymorph behavior, you need to use pointers like this:
Animal * a = new Animal();
Animal * w = new Wolf();
a->eat();
w->eat();
<...>
delete a;
delete w;
Provided the way you have it now, the behavior is right, because both variables clearly have different types.
Polymorphism works by identifying the type of object that an instance actually refers to.
In your case, your actual animals are as follows:
Animal a; //a is an animal.
Wolf w; //w is a wolf.
So, you're not using polymorphism at all.
What you need to do is more like this:
//Create a couple animal pointers.
Animal* a;
Animal* b;
//Create an animal instance and have a point to it.
a = new Animal();
//Create a wolf instance and have b point to it.
b = new Wolf();
//Calls Animal::eat as a is an animal.
a->eat();
//Calls Wolf::eat as a is a wolf.
b->eat();
Note that you can use pointers or references to achieve this use of polymorphism.
That is why you should usually pass objects by const-reference when working with class types.
//Will call Animal::eat or Wolf::eat depending on what animal was created as.
void foo(const Animal& animal) {
animal.eat();
}
//Will always call Animal::eat and never Wolf::eat since this isn't a reference or
//a pointer. Will also "slice" a Wolf object.
void foo(Animal animal) {
animal.eat();
}
Note that slicing means it will turn a more derived class (wolf) into a less derived copy of that class (animal) indiscriminately which can be very misleading and unexpected.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With