In the following code, why does the last call of eat() on the reference c return "An animal b is eating." ? From my understanding, c is a reference to instance b of the derived class Dog and eat() is a virtual function. So it should have returned "A dog b is eating."
#include <string>
#include <iostream>
using namespace std;
class Animal
{
protected:
string name;
public:
Animal( string _name ):
name(_name)
{
}
virtual void eat()
{
cout << "An animal " << name << " is eating." << endl;
}
};
class Dog : public Animal
{
public:
Dog( string _name ):
Animal(_name)
{
}
void eat()
{
cout << "A dog " << name << " is eating." << endl;
}
};
int main( int argc , char ** argv )
{
Animal a("A");
a.eat();
Dog b("b");
b.eat();
Animal & c = a;
c.eat();
c = b;
c.eat();
return 0;
}
This is the output:
An animal A is eating.
A dog b is eating.
An animal A is eating.
An animal b is eating.
Because you can't rebind references. Once you initialized them, their name always refers to the object you have initialized them with.
An object can have a name, e.g.
Animal a("A");
creates an object of typeAnimal
and introduces a namea
which refers to this object.References on the other hand introduce names without introducing objects (let's not consider temporaries):
Concerning the assignment:
This last assignment takes the object referred to by
b
, and copies its sub-object of typeAnimal
to the object whichc
refers to. Asa
andc
are equivalent, that's the same objecta
refers to. Therefore,a.name
is set to"B"
.The virtual function call
c.eat()
of course operates on an id-expression (c
) whose dynamic type isAnimal
- the same type asa
- therefore,Animal::eat
is called instead ofDog::eat
.In C++, reference cannot be rebind to other object once it is being initialized.
c
is still an alias of objecta
, which is anAnimal
, therefore, you saw the output which is expected.A reference is an alias for an object. After you bind a reference to an object (and that must happen at initialization time), what you do on the reference is done on the object being referenced.
In particular, you cannot re-bind a reference that has been already bound to an object and let it reference a different object. Thus, the following assignment (because that's an assignment, not an initialization):
Is equivalent to the following:
Since
c
is a reference to objecta
. The above assignment results in slicing, which is not what you wanted:c
won't be a reference bound tob
, but it will still be a reference bound toa
, to whichb
has been assigned.You cannot re-bind a reference once you have bound it, so you have to use pointers instead of references:
Now it will work exactly as you have wished it.
In order to make use of the dynamic polymorphism provided by virtual functions (distinguishing between derived and base classes during runtime), you need to access the derived class object via the base class pointer or reference.
I've commented out your code where confusion might have taken place: