0

Why the virtual makeNoise method of the base class is called instead of the method of the inherited class when I iterate through the list of Animal objects in following code. If I call directly the makeNoise method from the inherited objects then the right out put is printed out.

#include <iostream>
#include <list>

class Animal {
public:
  Animal() {
  }
  virtual ~Animal() {
  }

  virtual void makeNoise() {
    std::cout << "This animal makes no sound." << std::endl;
  }
};

class Dog: public Animal {
public:
  virtual void makeNoise() {
    std::cout << "Wuf!" << std::endl;
  }
};

class Cat: public Animal {
public:
  virtual void makeNoise() {
    std::cout << "Maouw!" << std::endl;
  }
};

int main() {
  std::list<Animal> listOfAnimals;
  Animal * cat = new Cat();
  Animal * dog = new Dog();
  listOfAnimals.push_back(*cat);
  listOfAnimals.push_back(*dog);

  for (std::list<Animal>::iterator it = listOfAnimals.begin();
      it != listOfAnimals.end(); ++it) {
    it->makeNoise();
  }

  cat->makeNoise();
  dog->makeNoise();

  return 0;
}

The output looks like:

This animal makes no sound.
This animal makes no sound.
Maouw!
Wuf!

I would expect the noises of Cat and Dog to be printed out also while iterating. That is the functionality of virtual method as I would understand it. Does the type definition of the list affect it somehow?

Miitsu
  • 9
  • 2
  • 4
    `std::list` doesn't use polymorphism. You need a reference or a pointer in order to have polymorphism. – bolov Jun 02 '15 at 11:29
  • 1
    you might want to read up on [object slicing](http://stackoverflow.com/questions/274626/what-is-object-slicing) – Sander De Dycker Jun 02 '15 at 11:30
  • @bolov as std::list can't contain references only way to do this is by pointers – W.F. Jun 02 '15 at 11:30
  • 1
    @bolov: That's actually not true. What you need is a reference or pointer in order not to slice your object and obtain a whole new, base-type, object. Polymorphism itself doesn't care about references or pointers: it's a fundamental fact of user-defined types in C++. – Lightness Races in Orbit Jun 02 '15 at 11:31
  • @Miitsu: `listOfAnimals.push_back(*cat);` this is the code which should have made you suspicious! – Lightness Races in Orbit Jun 02 '15 at 11:31
  • @LightnessRacesinOrbit yes, needing pointers or references is a consequence and not a definition of polymorphism. I still stand by my affirmation. You need a reference or a pointer to to have polymorphism (read: you can't obtain it any other way) – bolov Jun 02 '15 at 11:35
  • @bolov: Again, no you don't: `(*static_cast(new Dog())).makeNoise();` ([live demo](http://coliru.stacked-crooked.com/a/d887e9a4f6d0c5fd)) (sorry about the memory leak :P) What I'm saying is that you don't conditionally "obtain" or "have" polymorphism at all: it's there. Always. This is, of course, splitting hairs, but it helps to have an understanding about these things. – Lightness Races in Orbit Jun 02 '15 at 11:42
  • @Miitsu: Thank you for a perfect testcase, though! :) Other than the duplicate/lack-of-research, this is an excellently presented question. – Lightness Races in Orbit Jun 02 '15 at 11:42
  • @LightnessRacesinOrbit yes it is splitting hairs, and yes it is a healthy discussion. I personally understand and know what you are talking about, maybe my choice of words is misleading when you give a pedantic interpretation to my affirmation. Let me rephrase it: you don't make use of the language polymorphism unless you use pointers or references. e.g. `(static_cast(Dog())).makeNoise()` there is no polymorphism here. – bolov Jun 02 '15 at 11:51
  • @bolov: I dunno; that's kind of a weird way of looking at it. In `(*static_cast(new Dog())).makeNoise();`, the only pointer I've used was one from dynamic allocation, and it does not participate in polymorphism here whatsoever. Furthermore, there is no reference. (The only reason I obtained the pointer in the first place was to demonstrate how this can be achieved with a basic lvalue of type `Base`, which was most easily obtained via dereference). So I have effectively achieved polymorphism without pointers or references. This entire conversation is pretty pointless though ;) – Lightness Races in Orbit Jun 02 '15 at 11:54
  • @LightnessRacesinOrbit you cast to a pointer type. You accessed the object as if accessed through a pointer of another type. That's how I see this. – bolov Jun 02 '15 at 11:56
  • @bolov: I accessed the object through an lvalue of type `Animal`. I dereferenced the pointer long before the function call! The pointerness and the function call are completely decoupled here. They have no interaction. I guess your point is that I _did_ need to start off with a pointer to even perform that dereference and obtain that lvalue. I don't dispute those facts. :) But then you might as well say that polymorphism relies on there being oxygen in my house, because otherwise I couldn't write any code at all: I'd be dead! It's the same argument. – Lightness Races in Orbit Jun 02 '15 at 12:16

0 Answers0