0

Possible Duplicate:
Store two classes with the same base class in a std::vector

I have a Problem with inheritance in C++. Here I wrote a simple code to illustrate my problem:

//Animal.h
class Animal
{
public:

Animal();
~Animal();

virtual const void Eat();
};

//Bear.h
class Bear: public Animal
{
public:

Animal();
~Animal();

virtual const void Eat();
};

//Animal.cpp
const void Animal::Eat() {
}

//Bear.cpp
const void Animal::Eat() {
 //Do something
}

Now, in another class I declare a vector that should hold animals, and then I create a Bear and push it into my vector:

std::vector<Animal> a;
Bear b;
a.push_back(b);

The problem is now, that when I traverse my animal vector and try to call Eat(), the Eat method of the base class (animal) is called, but not the Bear Eat method.

Even trying with dynamic_cast it does not work: the dynamic_cast fails

dynamic_cast<Bear*>(&a.at(0));

What am I doing wrong? Is it because I lack copy constructor?

Community
  • 1
  • 1
ISTB
  • 1,799
  • 3
  • 22
  • 31

2 Answers2

4

You have to create a vector that holds animal (smart) pointers instead.

A vector of objects suffers from object slicing.

I'm assuming the void Animal::Eat() in Bear.cpp is a typo, otherwise your code wouldn't compile.

Also, const void? You want to make sure you don't modify anything?

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • An interesting question would be if C++11 (where vector uses move semantics) still has this problem. Actually it should be "magically" fixed, I think. After all, no Animal should be copy-created then, but the Bear taken as is (including the vtable, presumably)? – Damon Aug 20 '12 at 08:50
  • @Damon that doesn't even come into question. When you declare `std::vector` you explicitly say you want `Animal` objects. You'll no longer have Bears. – Luchian Grigore Aug 20 '12 at 08:51
  • @Damon, try think how you will store it. (and how operator[] will be implemented) – RiaD Aug 20 '12 at 08:55
1

You need two things to enable polymorphism: virtual functions and pointers. You don't have pointers. Your std::vector must be a vector of Animal* (or std::unique_ptr in C++11), not Animal.

std::vector<Animal*> a;
Bear b;
a.push_back(b);
a[0] -> eat();

Then, your bear function eat() is with Animal::. Correct it.

In addiction, also the destructor must be virtual: destructors calls must be polymorphic as well.

  • I thouhgt about slicing problem but I did not expected that pointers will solve the problem. Thanks to all, I learned something new – ISTB Aug 20 '12 at 09:09
  • But I am still curious, what happens when I put bear in animal vector? Does it call the base copy constructor and puts animal instead of bear? – ISTB Aug 20 '12 at 09:11
  • @ISTB Bear IS an Animal (because of the inheritance relation). So if you put a Bear in Animal (and not Animal*) is like to make Animal a = b where b is a Bear: you can do this, but you copy in Animal only some information of Bear (the members they have in common). Sincerely, I don't know if in this case it is called only the constructor of Animal or if it is called the constructor of Bear and then we have a partial copy of Bear in Animal as I said. The result is the same: you don't have a Bear but an Animal: so eat() of Animal is called. –  Aug 20 '12 at 09:17
  • Yes, I think that first the Animal constructor is called and then the copy constructor which of course copies only "animal" information of bear but not bears information – ISTB Aug 20 '12 at 09:31