我也被类似的代码迷住了——一拳。这是“为什么我要为函数调用赋值,为什么编译器对此感到满意?” 我问自己。但是,当您查看“背后”发生的事情时,这确实是有道理的。
正如cpp和其他人指出的那样,左值是具有地址的“内存位置”,我们可以为它们赋值。您可以在 Internet 上找到有关左值和右值主题的更多信息。
当我们查看函数时:
int& fun()
{
static int x = 10;
return x;
}
我将 & 移到了类型上,所以很明显我们正在返回对 int 的引用。
我们看到我们有x,它是左值 - 它有地址,我们可以分配给它。它也是静态的,这使它变得特别 - 如果它不是静态的,变量的生命周期(范围)将以离开函数时堆栈展开而结束,然后引用可以指向宇宙中存在的任何黑洞。然而,由于x是静态的,即使在我们离开函数之后(以及当我们再次回到函数时)它也会存在,并且我们可以在函数之外访问它。
我们正在返回对 int 的引用,并且由于我们返回x,它是对x的引用。然后我们可以使用引用来改变函数外部的x 。所以:
int main()
{
fun();
我们只是调用函数。变量x(在 fun 函数的范围内)被创建,它被赋值为 10。即使在函数离开后,它的地址和值仍然存在——但我们不能使用它的值,因为我们没有它的地址。
fun() = 30;
我们调用该函数,然后更改x的值。x值通过函数返回的引用进行更改。注意:函数首先被调用,并且只有在函数调用完成后才会发生分配。
int& reference_to_x = fun(); // note the &
现在我们(最终)保留对函数返回的x的引用。现在我们可以在不先调用函数的情况下更改x 。(reference_to_x可能与 fun 函数中的x具有相同的地址)
int copy_of_x = fun(); // no & this time
这次我们创建了新的 int 并且我们只是复制了x的值(通过引用)。这个新的 int 有自己的地址,它不像reference_to_x那样指向x。
reference_to_x = 5;
我们通过引用将x赋值为 5,我们甚至没有调用该函数。copy_of_x没有改变。
copy_of_x = 15;
我们将新的 int 更改为值15。x没有更改,因为copy_of_x有自己的地址。
}
正如6502和其他人指出的那样,我们使用类似的方法,通过容器和自定义覆盖返回大量引用。
std::map<std::string, std::string> map = {};
map["hello"] = "Ahoj";
// is equal to
map.operator[]("hello") = "Ahoj"; // returns reference to std::string
// could be done also this way
std::string& reference_to_string_in_map = map.operator[]("hello");
reference_to_string_in_map = "Ahoj";
我们使用的 map 函数可以有这样的声明:
std::string& map::operator[]( const std::string& key ); // returns reference
我们没有指向我们“存储”在 map 中的字符串的地址,所以我们调用 map 的这个重写函数,将 key 传递给它,以便 map 知道我们想要访问哪个字符串,并返回对该字符串的引用,这我们可以用来改变值。注意:再次调用该函数,并且只有在它完成后(map 找到正确的字符串并返回对它的引用)分配才会发生。就像 fun() = 10 一样,只是更漂亮......
希望这可以帮助那些即使在阅读其他答案后仍然无法理解所有内容的人......