4

假设我有以下代码:

#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;
}

当我运行它时,我得到以下输出(如预期的那样):

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

但是,在第 31 行,如果我取出“Account &a”中的“&”,使其变为:

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

我得到这个输出:

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

怎么会?我想在返回引用时,“&”是多余的/不是必需的?我是否从根本上误解了引用在 C++ 中的工作方式?

编辑:谢谢,我现在明白为什么两者不同了。但是,那么我不应该这样做:

Account GetAccount()
{
    return mainAccount;
}

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

但是,当我运行它时,我收到一个错误:

无标题:在函数“int main()”中:

无标题:31:错误:从“Account”类型的临时变量中“Account&”类型的非常量引用无效初始化</p>

4

5 回答 5

3

我想在返回引用时,“&”是多余的/不是必需的?

你想错了。

考虑这两条不同的线:

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

Account a = GetAccount(); // Line 31

首先,您声明一个被调用的引用,该引用a绑定到函数返回的对象GetAccount

在第二个中,您声明一个a由函数返回的对象复制初始化的对象GetAccount

从根本上说:一个声明一个引用,另一个声明一个对象。


编辑:回答后续问题:

我可以&从函数声明中的返回类型中删除吗GetAccountAccount GetAccount() { return mainAccount; }

你当然可以删除&,但是你的行为会改变。考虑这两个函数:

Account GetAccount() { return mainAccount; }

Account &GetAccount() { return mainAccount; }

首先,您返回一个已从该对象复制初始化的临时mainAccount对象。在第二个中,您返回对该mainAccount对象的引用。

  • 如果你想a成为一个参考mainAccount,你需要&在这两个地方。

  • 如果您想a成为 的副本mainAccount,则不需要&在 的声明中a在这种情况下,另一个声明无关紧要。

  • 如果您想a成为对编译器生成的临时值的引用(提示:您不这样做),请声明awith &,但GetAccount不声明。

于 2012-09-06T20:25:57.253 回答
2

您返回一个引用,然后使用该引用创建一个新对象。a是使用从返回的引用进行复制初始化的新对象GetAccount

请记住,引用是别名。这就像在说:

int x = 0;
int& y = x;

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

z在这种情况下不引用x也不y,因为z它本身不是引用。

所以:

x = 1;

将同时修改xy,但z仍为 0。

于 2012-09-06T20:23:01.860 回答
2

在这两种情况下,您都会返回一个引用,但您使用它的方式有所不同:

Account &a = GetAccount(); 

在这种情况下,您使用引用来初始化另一个引用,a对原始数据进行引用。

Account a = GetAccount(); 

在这种情况下,您使用返回的引用来初始化 type 的对象Account,而不是对 Account 的引用。因此,您将原始对象复制到新创建的a.

于 2012-09-06T20:26:18.427 回答
0

这很重要。

这个版本

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

创建帐户的副本,而不是参考。因此,在更改余额时,您更改的是副本的余额,而不是原始的余额。

于 2012-09-06T20:25:17.317 回答
0

从标题中回答问题:不直接。

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

顺便说一句,&这里不用作运算符。它修改Account类型。它可以用作一元和二元运算符,例如 in&obj5 & 6。当用作运算符时,它必须出现在表达式之前或之间。

于 2012-09-07T08:35:55.823 回答