Learning C++: returning references AND getting around slicing

前端 未结 8 1521
醉酒成梦
醉酒成梦 2021-02-14 00:06

I\'m having a devil of a time understanding references. Consider the following code:

class Animal
{
public:
    virtual void makeSound() {cout << \"rawr\"         


        
8条回答
  •  日久生厌
    2021-02-14 00:35

    But let's say that I want a function that returns an Animal value that is really a Dog.

    1. Do I understand correctly that the closest that I can get is a reference?

    Yes, you are correct. But I think the problem isn't so much that you don't understand references, but that you don't understand the different types of variables in C++ or how new works in C++. In C++, variables can be an primitive data (int,float,double,etc.), an object, or a pointer/reference to a primitive and/or object. In Java, variables can only be a primitive or a reference to an object.

    In C++, when you declare a variable, actual memory is allocated and associated with the variable. In Java, you have to explicitly create objects using new and explicitly assign the new object to a variable. The key point here though is that, in C++, the object and the variable you use to access are not the same thing when the variable is a pointer or reference. Animal a; means something different from Animal *a; which means something different from Animal &a;. None of these have compatible types, and they are not interchangeable.

    When you type, Animal a1 in C++. A new Animal object is created. So, when you type Animal a2 = a1;, you end up with two variables (a1 and a2) and two Animal objects at different location in memory. Both objects have the same value, but you can change their values independently if you want. In Java, if you typed the same exact code, you'd end up with two variables, but only one object. As long as you didn't reassign either of the variables, they would always have the same value.

    1. Furthermore, is it incumbent upon the one using the rFunc interface to see that the reference returned is assign an Animal&? (Or otherwise intentionally assign the reference to an Animal which, via slicing, discards polymorphism.)

    When you use references and pointers, you can access an object's value without copying it to where you want to use it. That allows you to change it from outside the curly braces where you declared the object into existence. References are generally used as function parameters or to return an object's private data members without making a new copy of them. Typically, when you recieve a reference, you don't assign it to anything. Using your example, instead of assigning the reference returned by rFunc() to a variable, one would normally type rFunc().makeSound();.

    So, yes, it is incumbent on the user of rFunc(), if they assign the return value to anything, to assign it to a reference. You can see why. If you assign the reference returned by rFunc() to a variable declared as Animal animal_variable, you end up with one Animal variable, one Animal object, and one Dog object. The Animal object associated with animal_variable is, as much as possible, a copy of the Dog object that was returned by reference from rFunc(). But, you can't get polymorphic behavior from animal_variable because that variable isn't associated with a Dog object. The Dog object that was returned by reference still exists because you created it using new, but it is no longer accessible--it was leaked.

    1. How on earth am I supposed to return a reference to a newly generated object without doing the stupid thing I did above in rFunc? (At least I've heard this is stupid.)

    The problem is that you can create an object in three ways.

    { // the following expressions evaluate to ...  
     Animal local;  
     // an object that will be destroyed when control exits this block  
     Animal();  
     // an unamed object that will be destroyed immediately if not bound to a reference  
     new Animal();  
     // an unamed Animal *pointer* that can't be deleted unless it is assigned to a Animal pointer variable.  
     {  
      // doing other stuff
     }  
    } // <- local destroyed
    

    All new does in C++ is create objects in memory where it won't be destroyed until you say so. But, in order to destroy it, you have to remember where it was created at in memory. You do that by creating a pointer variable, Animal *AnimalPointer;, and assigning the pointer returned by new Animal() to it, AnimalPointer = new Animal();. To destroy the Animal object when you are done with it, you have to type delete AnimalPointer;.

提交回复
热议问题