inheritance doesn't works as expected

T

Tony Johansson

Hello Experts!

I have some class definition and a main below.
This is a strange problem.
When cout is executing in the for loop below locating in main I get this
print out on the screen
Bird eats Bird food
Cat eats Birds
for(int i = 0; i<sizeof p/sizeof *p; i++)
cout << p->type() << " eats " << p->eats()->foodType() << endl;
The strange thing is that it doesn't matter what return type I have on the
eats method I always get
the same answer which is the same as above.

I mean these two gives the same output for class Bird when foodType() is
called in the for loop
BirdFood* eats()
PetFood* eats()

and these two gives the same output for class Cat when foodType() is called
in the for loop
CatFood* eats()
PetFood* eats()

Just to try to understand this I removed the virtual for this foodType
method in class PetFood.
Now I always get the same output which is
Bird eats Pet food
Cat eats Pet food.
it doesn't matter if I have
CatFood* eats()
or
PetFood* eats()
In class Cat.

I mean if I don't use virtual I will be using the static type and not the
dynamic type.
This would mean that if I return CatFood* eats()
I would be calling foodType in class CatFood and not in class PetFood.


//Class definitions
#include <iostream>
#include <string>
using namespace std;

class PetFood
{
public:
string foodType() const
{ return "Pet food"; }
};

class Pet
{
public:
virtual string type() const = 0;
virtual PetFood* eats() = 0;
};

class Bird : public Pet
{
public:
string type() const
{ return "Bird"; }

class BirdFood : public PetFood
{
public:
string foodType() const
{ return "Bird food"; }
};

PetFood* eats()
{ return &bf; }

private:
BirdFood bf;
};

class Cat : public Pet
{
public:
string type() const
{ return "Cat"; }

class CatFood : public PetFood
{
public:
string foodType() const
{ return "Birds"; }
};

CatFood* eats()
{ return &cf; }

private:
CatFood cf;
};

#include <iostream>
#include "pet.h"
using namespace std;
int main()
{
Bird b;
Cat c;
Pet* p[] = {&b, &c};

for(int i = 0; i<sizeof p/sizeof *p; i++)
cout << p->type() << " eats " << p->eats()->foodType() << endl;
return 0;
}

Many thanks

//Tony
 
J

Josh Mcfarlane

Tony Johansson wrote:
[snip]

Judging from the number of questions you're posting per day on this
newsgroup, you may want to consider another method of learning. If
you're taking a class, it might be time to talk to your professor about
the things you're asking about on the list. If you're using a book, you
may want to consider getting a new one.

Not to be mean, but these questions all seem like they'd come off a
homework assignment from someone's programming course. Always a few
theory questions and then an problem.
 
V

Victor Bazarov

Tony said:
I have some class definition and a main below.
This is a strange problem.

There is nothing strange about it. And there is no problem. The program
behaves _absolutely_ according to language rules.
When cout is executing in the for loop below locating in main I get this
print out on the screen
Bird eats Bird food
Cat eats Birds
for(int i = 0; i<sizeof p/sizeof *p; i++)
cout << p->type() << " eats " << p->eats()->foodType() << endl;
The strange thing is that it doesn't matter what return type I have on the
eats method I always get
the same answer which is the same as above.

I mean these two gives the same output for class Bird when foodType() is
called in the for loop
BirdFood* eats()
PetFood* eats()


Since 'BirdFood' is a derived class of 'PetFood', a pointer to it is
"covariant" to the pointer its base.
and these two gives the same output for class Cat when foodType() is called
in the for loop
CatFood* eats()
PetFood* eats()

Same thing.

In both cases, 'eats' in the derived class is the overrider for the base
class' function 'eats'.

The return value type comes into play if you call your function through
a pointer or a reference of either the base class or the derived class.
That's the main reason to have covariant return value types.
Just to try to understand this I removed the virtual for this foodType
method in class PetFood.

So, you disabled polymorphism. Now, 'BirdFood' or 'CatFood' are not
polymorphic types any longer. When 'eats' returns a pointer to 'PetFood',
that's how the object is treated. A call to 'foodType' always resolves
into 'PetFood::foodType'.

If you keep 'virtual', then the call will be resolved _polymorphically_,
according to the type with which the object (pointed to by 'PetFood*')
was _constructed_. In case of 'BirdFood' 'BirdFood::foodType' is called,
in case of 'CatFood' 'CatFood::foodType'.
Now I always get the same output which is
Bird eats Pet food
Cat eats Pet food.
it doesn't matter if I have
CatFood* eats()
or
PetFood* eats()
In class Cat.

Yes, it doesn't matter. The returned pointer is of type 'PetFood*',
since you call it through a _pointer_to_Pet_. Had you called 'eats'
through a pointer to 'Cat', you'd get 'CatFood*' (if 'eats' had been
declared to have covariant return value types).
I mean if I don't use virtual I will be using the static type and not the
dynamic type.
Right.

This would mean that if I return CatFood* eats()
I would be calling foodType in class CatFood and not in class PetFood.

No. The return value type of Pet::eats is not CatFood*, it's PetFood*.
You would only be calling 'CatFood::foodType' _iff_ the function is
virtual.

V
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,049
Latest member
Allen00Reed

Latest Threads

Top