A reference is
not the address of a variable - they happen to use the same character in their syntax (&), but they are completely different. When you do
you are saying "pFoo will point to the address of a Foo, and we are going to initialize it with the address of someFoo". A reference can be thought of as a way to provide just a new name for the same variable. In the case:
1 2
|
Foo someFoo;
Foo &refFoo = someFoo;
|
Notice you are initializing it to someFoo, not the address of someFoo. After this line, refFoo and someFoo can be used 100% interchangeably, and they both represent the exact same object internally - changes to 1 affect the other. This is slightly different from pointers, in that you can re-assign "pFoo" to another object, and it will not affect the original someFoo object (though you
can affect the original someFoo object if you did something like pFoo->size = 10).
Onto the actual question... @Stewbond as well
as peter correctly stated, the code
1 2
|
Numbers numbers; // [1]
numbers = Numbers( 5, 10 ); // [2]
|
actually calls 3 functions: at [1], the 'numbers' object is constructed using the default constructor fo Numbers. At [2], first a whole new object is created with "Numbers(5, 10)". This object is not bound to a variable; it is called a 'temporary' or 'rvalue', and because there is no variable associated with this newly created object, it goes out of scope as soon as the expression exits. The 3rd function being (attempting to be) called is operator=(Numbers &). You are trying to pass in this newly created rvalue object to operator=, but operator= expects a reference to a 'Numbers' object, which may be modified inside the operator= method (by nature of that method not taking a const parameter). But it doesn't make sense to allow editing of a Numbers object that is temporary, as by definition it isn't sticking around after the function exits. To fix your code in main, you can instead write:
1 2 3
|
Numbers numbers;
Numbers temp(5, 10);
numbers = temp;
|
Now your code will work, because operator= has something to bind the parameter to - the 'temp' variable. Alternately, you can (and should, as good practice) change operator= to take a
const Numbers &
, for 2 reasons: 1 is that since the value isn't actually being modified, it's the right thing to do, and 2 that a const reference can accept r-values or even construct entirely new objects as needed. A good example is:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
void Foo1 (string & str)
{
}
void Foo2(const string & str)
{
}
...
Foo1("Hello"); // Won't compile - we want a string, not a const char *
Foo2("World"); // will compile - compiler is allowed to generate a temporary string object, and use the string::string(const char *) constructor to initialize
|
As a final note: MSVC seems to allow binding of an rvalue to a non-const reference. This behavior doesn't seem 100% wrong to me, as the lifetime of the temporary extends until the end of the expression in which it is created, which will be after the function returns. It is however non-standard (I believe), and perhaps a somewhat 'bad practice'.