user1516425
user1516425

Reputation: 1571

When returning a reference to an object from C++, is it necessary to use the "&" operator in the return variable?

Say I have the following code:

#include <iostream>

using namespace std;

class Account
{
private:
    float balance;

public:
    Account() { balance = 0.0; };
    float GetBalance() { return balance; };
    void SetBalance(float newBalance) { balance = newBalance; };
};

Account mainAccount;

Account& GetAccount()
{
    return mainAccount;
}

void PrintAccountInfo()
{
    cout << "mainAccount's balance is " << mainAccount.GetBalance() << endl;
}

int main()
{
    PrintAccountInfo();
    Account &a = GetAccount(); // Line 31
    a.SetBalance(30.0);
    PrintAccountInfo();
    return 0;
}

When I run it, I get the following output (as expected):

mainAccount's balance is 0
mainAccount's balance is 30

However, on line 31, if I take out the "&" in the "Account &a", to make it this:

Account a = GetAccount(); // note lack of "&"

I get this output:

mainAccount's balance is 0
mainAccount's balance is 0

How come? I thought when returning a reference, the "&" is redundant / not necessary? Am I fundamentally misunderstanding how references work in C++?

EDIT: Thanks, I understand now why the two are different. However, then shouldn't I be able to do this:

Account GetAccount()
{
    return mainAccount;
}

int main()
{
    Account &a = GetAccount();
    // ....
}

However, when I run that, I get an error:

untitled: In function ‘int main()’:

untitled:31: error: invalid initialization of non-const reference of type ‘Account&’ from a temporary of type ‘Account’

Upvotes: 4

Views: 155

Answers (5)

MSalters
MSalters

Reputation: 179779

To answer the question from the title: Not directly.

typedef Account& AccountRef; // Hiding here
AccountRef GetAccount()
{
    return mainAccount;
}

BTW, & isn't used as an operator here. It modifies the Account type. It can be used as an unary and binary operator, e.g. in &obj or 5 & 6. When used as an operator, it must appear before or between expressions.

Upvotes: 0

Robᵩ
Robᵩ

Reputation: 168596

I thought when returning a reference, the "&" is redundant / not necessary?

You thought wrong.

Consider these two different lines:

Account &a = GetAccount(); // Line 31

Account a = GetAccount(); // Line 31

In the first, you declare a reference called a which is bound to the object returned by the function GetAccount.

In the second, you declare an object a which is copy-initialized by the object returned by the function GetAccount.

Fundamentally: one declares a reference, the other declares an object.


EDIT: Answering the follow-on question:

"can I remove the & from the return type in the declaration of the GetAccount function: Account GetAccount() { return mainAccount; }"

You certainly can remove the &, but then your behavior will change. Consider these two functions:

Account GetAccount() { return mainAccount; }

Account &GetAccount() { return mainAccount; }

In the first, you return a temporary object which has been copy-initialized from the mainAccount object. In the second you return a reference to the mainAccount object.

  • If you want a to be a reference to mainAccount, you need & in both places.

  • If you want a to be a copy of mainAccount, you need no & in the declaration of a. The other declaration won't matter in this case.

  • If you want a to be a reference to a compiler-generated temporary value (hint: you don't), declare a with &, but GetAccount without.

Upvotes: 3

Luchian Grigore
Luchian Grigore

Reputation: 258548

You return a reference, but you then create a new object using that reference. a is the new object that gets copy-initialized using the reference returned from GetAccount.

Remember, a reference is an alias. It's like saying:

int x = 0;
int& y = x;

int z = y;
//is equivalent to
z = x;

z doesn't refer to x nor y in this case, because z itself isn't a reference.

So:

x = 1;

would modify both x and y, but z would still be 0.

Upvotes: 2

Grizzly
Grizzly

Reputation: 20191

In both cases you return a reference, but there is a difference in how you use it:

Account &a = GetAccount(); 

In this case you use the reference to initialize another reference, making a a reference to the original Data.

Account a = GetAccount(); 

In this case you use your returned reference to initialize an object of type Account, instead of a reference to Account. Therefore you copy the original object into the newly created a.

Upvotes: 2

Bo Persson
Bo Persson

Reputation: 92211

It does matter.

This version

Account a = GetAccount(); // note lack of "&"

creates a copy of the account, not a reference. Therefore when changing the balance, you change the balance of the copy, not the original.

Upvotes: 0

Related Questions