Can anyone explain the output of the following code?
#include <iostream>
#include <string>
class Animal
{
public:
Animal(const std::string & name) : _name(name) { }
~Animal() { }
virtual void printMessage() const
{
std::cout << "Hello, I'm " << _name << std::endl;
}
private:
std::string _name;
// other operators and stuff
};
class Cow : public Animal
{
public:
Cow(const std::string & name) : Animal(name) { }
~Cow() { }
virtual void printMessage()
{
Animal::printMessage();
std::cout << "and moo " << std::endl;
}
};
int main() {
Cow cow("bill");
Animal * animal = &cow;
cow.printMessage();
animal->printMessage();
}
The output is
Hello, I'm bill
and moo
Hello, I'm bill
I don't understand why. The pointer animal points at an object of type Cow. printMessage is a virtual function. Why isn't the implementation of the Cow class the one that is called?
It took me a while to understand Peter Alexander's hiding answer, but another way to understand it is as follows:
Say that you mispelled the method name in the Cow class, but spelled it correctly in Animal class:
then when you have an
you can ONLY call
but you CANNOT call
because mispelledPrintMessage() doesn't exist in the Animal class. Its a brand new method in the Cow class, so it cannot be polymorphically called thru a base pointer.
So having the Animal method have const in the signature, but not in Cow method is kinda analogous to a slightly mispelled method name in the derived class.
PS: Another 4th solution (1 making both methods const, 2 making both methods non-const, or 3 using new 2011 override keyword), is to use a cast, to force the Animal pointer into a Cow pointer:
But this is a very ugly HACK, and I would not recommend it.
PS: I always try to write my toString() methods with const in the signature in the Base class and all derived classes for this very reason. Plus, having const in the toString() signature allows you call toString() either with a const or non-const object. Had you instead left out the const, and tried to pass call toString() with a const object, GCC compiler would complain with the discards qualifiers error message:
for this code:
So, in conclusion, since Cow doesn't change any data members, the best solution probably is to add const to printMessage() in derived Cow class, so that both BASE Animal and DERIVED Cow classes have const in their signatures.
-dennis bednar -ahd 310
Just tried it. Add the
const
to the Cow class and it will work.i.e.
virtual void printMessage () const
for both classes.Cow
isn't overriding the virtual function fromAnimal
because it has a different signature. What's actually happening is thatCow
is hiding the function inAnimal
.The result of this is that calling
printMessage
on anAnimal
will just use the version inAnimal
, regardless of the one inCow
(it isn't overriding it), but calling it fromCow
will use the one inCow
(because it hides the one fromAnimal
).To fix this, remove the
const
inAnimal
, or add theconst
inCow
.In C++ 2011, you will be able to use the
override
keyword to avoid subtle traps like this:Notice the added
override
afterprintMessage()
. This will cause the compiler to emit an error ifprintMessage
doesn't actually override a base class version. In this case, you would get the error.virtual in subclass-->no need. You just add const to function in subclass to make it same signature
Correction to Dennis's post.
Note you state as a solution you can cast the animal (which is a Animal*) to a Cow*. However, once a Cow* your printMessage from the Animal class will not be available. Therefore ((Cow*)animal)->printMessage() needs to be ((Cow*)animal)->mispelledPrintMessage()
You have two different versions of
printMessage
, one which isconst
and one which isn't. The two are unrelated, even though they have the same name. The new function inCow
hides the one inAnimal
, so when you call it directly the compiler only considers theCow
version.