C++ 修改通过引用传递的 class 不会更改原始对象
C++ modifying a class passed by reference does not change the original object
我有一个包含几个实例变量的 class A 和一个引用 class 并更改实例变量的 class B。在 class B 更改这些变量后,您会认为这些变量会在 class 的原始实例中发生更改,但在这种情况下它们不会。为什么会发生这种情况,我该如何解决?
class Foo {
public:
int x;
int y;
Foo() {
}
Foo(int x, int y) {
this->x = x;
this->y = y;
}
};
class Bar {
public:
Foo foo;
Bar() {
}
Bar(Foo& foo) {
this->foo = foo;
}
void Swap() {
int tmp = foo.x;
foo.x = foo.y;
foo.y = tmp;
}
};
int main()
{
Foo foo(4, 8);
Bar bar(foo);
std::cout << "this is x: " << foo.x << std::endl; //prints 4
std::cout << "this is y: " << foo.y << std::endl; //prints 8
bar.Swap();
std::cout << "this is x: " << foo.x << std::endl; //prints 4, but should print 8
std::cout << "this is y: " << foo.y << std::endl; //prints 8, but should print 4
}
您将对 foo 的引用传递给 bar 的构造函数,然后将您通过引用传递给 bar.foo.
的 foo 赋值(复制)
您想将其声明为对 Foo 对象的引用(或指针),而不是单独的 Foo 对象。
Class B
的构造函数确实通过引用获取 foo
(参数),但立即将其复制到 A
的单独实例中(特别是,进入 foo
成员); Swap
然后在 foo
成员上工作,如上所述,它只是原始对象的副本。
为了使您的代码按照您的预期运行,您甚至必须使成员 foo
成为引用(或指针):
class Bar {
public:
Foo &foo;
Bar() {
}
Bar(Foo& foo) : foo(foo) {
}
(注意我必须使用 the member initialization list syntax because references cannot be default-initialized and then reseated)
问题就在这里
Foo foo;
Bar(Foo& foo) {
this->foo = foo;
}
即使您通过引用获取 foo
参数,您也将其分配给了一个非引用值,这会产生一个副本并说明您提出的问题。解决方案的第一步也是通过引用声明您的实例字段。
Foo& foo;
但是当您尝试分配给它时,这会导致错误。为此,我们要使用一种特殊的构造函数初始化语法。它基本上与赋值相同,但执行构造而不是正常赋值。所以写你的构造函数如下。
Bar(Foo& foo) : foo(foo) {}
您还必须完全删除默认构造函数 Bar()
,因为大多数 C++ 编译器会拒绝可能导致未初始化引用的代码。
我有一个包含几个实例变量的 class A 和一个引用 class 并更改实例变量的 class B。在 class B 更改这些变量后,您会认为这些变量会在 class 的原始实例中发生更改,但在这种情况下它们不会。为什么会发生这种情况,我该如何解决?
class Foo {
public:
int x;
int y;
Foo() {
}
Foo(int x, int y) {
this->x = x;
this->y = y;
}
};
class Bar {
public:
Foo foo;
Bar() {
}
Bar(Foo& foo) {
this->foo = foo;
}
void Swap() {
int tmp = foo.x;
foo.x = foo.y;
foo.y = tmp;
}
};
int main()
{
Foo foo(4, 8);
Bar bar(foo);
std::cout << "this is x: " << foo.x << std::endl; //prints 4
std::cout << "this is y: " << foo.y << std::endl; //prints 8
bar.Swap();
std::cout << "this is x: " << foo.x << std::endl; //prints 4, but should print 8
std::cout << "this is y: " << foo.y << std::endl; //prints 8, but should print 4
}
您将对 foo 的引用传递给 bar 的构造函数,然后将您通过引用传递给 bar.foo.
的 foo 赋值(复制)您想将其声明为对 Foo 对象的引用(或指针),而不是单独的 Foo 对象。
Class B
的构造函数确实通过引用获取 foo
(参数),但立即将其复制到 A
的单独实例中(特别是,进入 foo
成员); Swap
然后在 foo
成员上工作,如上所述,它只是原始对象的副本。
为了使您的代码按照您的预期运行,您甚至必须使成员 foo
成为引用(或指针):
class Bar {
public:
Foo &foo;
Bar() {
}
Bar(Foo& foo) : foo(foo) {
}
(注意我必须使用 the member initialization list syntax because references cannot be default-initialized and then reseated)
问题就在这里
Foo foo;
Bar(Foo& foo) {
this->foo = foo;
}
即使您通过引用获取 foo
参数,您也将其分配给了一个非引用值,这会产生一个副本并说明您提出的问题。解决方案的第一步也是通过引用声明您的实例字段。
Foo& foo;
但是当您尝试分配给它时,这会导致错误。为此,我们要使用一种特殊的构造函数初始化语法。它基本上与赋值相同,但执行构造而不是正常赋值。所以写你的构造函数如下。
Bar(Foo& foo) : foo(foo) {}
您还必须完全删除默认构造函数 Bar()
,因为大多数 C++ 编译器会拒绝可能导致未初始化引用的代码。