inheritance doesn't works as expected

Discussion in 'C++' started by Tony Johansson, Aug 19, 2005.

  1. 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
     
    Tony Johansson, Aug 19, 2005
    #1
    1. Advertising

  2. 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.
     
    Josh Mcfarlane, Aug 19, 2005
    #2
    1. Advertising

  3. Tony Johansson wrote:
    > 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
     
    Victor Bazarov, Aug 19, 2005
    #3
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Dean R. Henderson
    Replies:
    1
    Views:
    393
    Dean R. Henderson
    Apr 25, 2005
  2. aditya

    why this C code did'nt works as expected

    aditya, Oct 11, 2004, in forum: C Programming
    Replies:
    8
    Views:
    281
    Randy Howard
    Oct 12, 2004
  3. Anand Ganesh
    Replies:
    5
    Views:
    2,706
    Anand Ganesh
    Feb 24, 2008
  4. KJF
    Replies:
    4
    Views:
    108
  5. jgabios
    Replies:
    5
    Views:
    153
    Jeremy J Starcher
    Apr 22, 2009
Loading...

Share This Page