在 C++ 中,为什么当我将一个引用变量重新分配给另一个引用变量时,它会创建该变量的副本?
In C++ why is it when I reassign a reference variable to a different reference variable it creates a copy of that variable instead?
struct configfs
{
int & foo;
configfs(int & foo_) : foo(foo_) {}
void set_foo(int & foo_)
{
foo = foo_;
}
};
int main() {
int a = 1;
configfs conf(a);
a = 3;
std::cout << conf.foo; // 3
std::cout << a; // 3
int b = 2;
conf.set_foo(b);
b = 9;
std::cout << conf.foo; // 2
std::cout << b; // 9
return 0;
}
当我用 int a
初始化 configfs
然后在主函数中改变 a 它也会改变 configfs.foo
。但是当我将 configfs.foo
重新分配给一个新的引用并在主函数中更改该引用时,行为是不同的。为什么?有没有办法让我 运行 conf.set_foo(b)
然后在主作用域中改变 b 时,它也会改变 conf.foo
?
引用只能在初始化期间“赋值”。它们不能像指针那样被“重定向”。初始化后,引用所指的内存保持不变,任何使用 =
的赋值都会导致对引用所指的内存调用赋值运算符。这就是它在 C++ 标准中指定的方式。
您可以使用自定义类型重写示例,并使用赋值运算符打印有关调用的信息:
template<class T>
struct configfs
{
T& foo;
configfs(T& foo_) : foo(foo_) {}
void set_foo(T& foo_)
{
foo = foo_; // this uses the assignment operator assigning to the variable foo is an alias for
}
};
// Type wrapping the int and printing out the operations applied
struct TestWrapper
{
TestWrapper(int value)
: value(value)
{
std::cout << "TestWrapper::TestWrapper(" << value << ")\n";
}
TestWrapper(TestWrapper const& other)
: value(other.value)
{
std::cout << "TestWrapper::TestWrapper(TestWrapper{" << other.value << "})\n";
}
TestWrapper& operator=(TestWrapper const& other)
{
std::cout << "TestWrapper::operator=(TestWrapper{" << other.value << "})\n";
value = other.value;
return *this;
}
int value;
};
std::ostream& operator<<(std::ostream& s, TestWrapper const& val)
{
s << val.value;
return s;
}
int main() {
TestWrapper a = 1;
configfs<TestWrapper> conf(a);
a = 3;
std::cout << conf.foo << '\n'; // 3
std::cout << a << '\n'; // 3
TestWrapper b = 2;
conf.set_foo(b); // TestWrapper::operator=(TestWrapper{2})
b = 9;
std::cout << conf.foo << '\n'; // 2
std::cout << b << '\n'; // 9
return 0;
}
当你写道:
conf.set_foo(b);
发生以下情况:
在对象conf
.
上调用了成员函数set_foo
此外,名为foo_
的引用参数绑定了名为b
的参数。也就是说,b
通过引用传递。
接下来遇到语句foo = foo_;
。这是一个赋值语句而不是初始化。它的作用是将参数 foo_
引用的值 赋给 数据成员 foo
引用的对象(这不过是 a
这里)。您可以通过在调用 set_foo
之后添加 std::cout<<a;
来 confirm this,如下所示:
int b = 2;
conf.set_foo(b);
std::cout<<a<<std::endl; //prints 2
这是因为对引用的操作实际上是对引用所绑定的对象的操作。这意味着当我们 分配 给一个引用时,我们正在分配给引用所指向的对象
被绑定。当我们获取引用的值时,我们实际上是在获取引用绑定到的对象的值。
注意:
一旦初始化,引用仍然绑定到它的初始对象。无法重新绑定引用以引用不同的引用
对象。
struct configfs
{
int & foo;
configfs(int & foo_) : foo(foo_) {}
void set_foo(int & foo_)
{
foo = foo_;
}
};
int main() {
int a = 1;
configfs conf(a);
a = 3;
std::cout << conf.foo; // 3
std::cout << a; // 3
int b = 2;
conf.set_foo(b);
b = 9;
std::cout << conf.foo; // 2
std::cout << b; // 9
return 0;
}
当我用 int a
初始化 configfs
然后在主函数中改变 a 它也会改变 configfs.foo
。但是当我将 configfs.foo
重新分配给一个新的引用并在主函数中更改该引用时,行为是不同的。为什么?有没有办法让我 运行 conf.set_foo(b)
然后在主作用域中改变 b 时,它也会改变 conf.foo
?
引用只能在初始化期间“赋值”。它们不能像指针那样被“重定向”。初始化后,引用所指的内存保持不变,任何使用 =
的赋值都会导致对引用所指的内存调用赋值运算符。这就是它在 C++ 标准中指定的方式。
您可以使用自定义类型重写示例,并使用赋值运算符打印有关调用的信息:
template<class T>
struct configfs
{
T& foo;
configfs(T& foo_) : foo(foo_) {}
void set_foo(T& foo_)
{
foo = foo_; // this uses the assignment operator assigning to the variable foo is an alias for
}
};
// Type wrapping the int and printing out the operations applied
struct TestWrapper
{
TestWrapper(int value)
: value(value)
{
std::cout << "TestWrapper::TestWrapper(" << value << ")\n";
}
TestWrapper(TestWrapper const& other)
: value(other.value)
{
std::cout << "TestWrapper::TestWrapper(TestWrapper{" << other.value << "})\n";
}
TestWrapper& operator=(TestWrapper const& other)
{
std::cout << "TestWrapper::operator=(TestWrapper{" << other.value << "})\n";
value = other.value;
return *this;
}
int value;
};
std::ostream& operator<<(std::ostream& s, TestWrapper const& val)
{
s << val.value;
return s;
}
int main() {
TestWrapper a = 1;
configfs<TestWrapper> conf(a);
a = 3;
std::cout << conf.foo << '\n'; // 3
std::cout << a << '\n'; // 3
TestWrapper b = 2;
conf.set_foo(b); // TestWrapper::operator=(TestWrapper{2})
b = 9;
std::cout << conf.foo << '\n'; // 2
std::cout << b << '\n'; // 9
return 0;
}
当你写道:
conf.set_foo(b);
发生以下情况:
在对象
上调用了成员函数conf
.set_foo
此外,名为
foo_
的引用参数绑定了名为b
的参数。也就是说,b
通过引用传递。接下来遇到语句
foo = foo_;
。这是一个赋值语句而不是初始化。它的作用是将参数foo_
引用的值 赋给 数据成员foo
引用的对象(这不过是a
这里)。您可以通过在调用set_foo
之后添加std::cout<<a;
来 confirm this,如下所示:
int b = 2;
conf.set_foo(b);
std::cout<<a<<std::endl; //prints 2
这是因为对引用的操作实际上是对引用所绑定的对象的操作。这意味着当我们 分配 给一个引用时,我们正在分配给引用所指向的对象 被绑定。当我们获取引用的值时,我们实际上是在获取引用绑定到的对象的值。
注意:
一旦初始化,引用仍然绑定到它的初始对象。无法重新绑定引用以引用不同的引用
对象。