Calling a virtual function on a reference

前端 未结 5 829
误落风尘
误落风尘 2021-01-25 08:06

In the following code, why does the last call of eat() on the reference c return \"An animal b is eating.\" ? From my

相关标签:
5条回答
  • 2021-01-25 08:34

    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):

    c = b;
    

    Is equivalent to the following:

    a = b;
    

    Since c is a reference to object a. The above assignment results in slicing, which is not what you wanted: c won't be a reference bound to b, but it will still be a reference bound to a, to which b has been assigned.

    0 讨论(0)
  • 2021-01-25 08:34

    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 type Animal and introduces a name a which refers to this object.

    References on the other hand introduce names without introducing objects (let's not consider temporaries):

    Animal& c = a; // a new name `c` which refers to the same object as `a`
    
    // another (evil) example:
    Animal& c = *(new Animal("C")); // `new` introduces an object without name
                                    // `c` now refers to this object
    

    Concerning the assignment:

    Animal & c = a;
    // the name `c` is now equivalent to the name `a`
    
    c = b; // equivalent to `a = b;`
    

    This last assignment takes the object referred to by b, and copies its sub-object of type Animal to the object which c refers to. As a and c are equivalent, that's the same object a 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 is Animal - the same type as a - therefore, Animal::eat is called instead of Dog::eat.

    0 讨论(0)
  • 2021-01-25 08:35
    Animal & c = a;
    c.eat();
    
    c = b; ///^^^
    c.eat();
    

    In C++, reference cannot be rebind to other object once it is being initialized. c is still an alias of object a, which is an Animal, therefore, you saw the output which is expected.

    0 讨论(0)
  • 2021-01-25 08:35

    You cannot re-bind a reference once you have bound it, so you have to use pointers instead of references:

    Animal *c = &a;
    c->eat();
    
    c = &b;
    c->eat();
    

    Now it will work exactly as you have wished it.

    0 讨论(0)
  • 2021-01-25 08:51

    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:

    int main( int argc , char ** argv )
    {
    
        Animal a("A");
        a.eat();
    
        Dog b("b");
        b.eat();
    
        // Make a reference (alias) to Animal object and set it to the object a. 
        // From this point on, whenever you write c, think "a".
        Animal & c = a;
        // So, this is a.eat()
        c.eat();
    
        // This is a = b (Animal = Dog): DANGER! SLICING! Here, the assignment operator
        // slices the derived object and only assigns the base object "part" (remember, 
        // read "a", where you see "c" in your code): 
        // a.operator=(const A& b)
        c = b;
        // a.eat() = a is object of type A, so naturally, here you call A::eat()
        c.eat();
    
        return 0;
    }
    
    0 讨论(0)
提交回复
热议问题