【问题标题】:C++ modifying a class passed by reference does not change the original objectC++修改通过引用传递的类不会改变原始对象
【发布时间】:2017-10-21 07:28:04
【问题描述】:

我有一个包含几个实例变量的类 A 和一个引用该类并更改实例变量的类 B。在 B 类更改这些变量之后,您会认为这些变量会在该类的原始实例中发生更改,但在这种情况下它们不会。为什么会发生这种情况,我该如何解决?

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
}

【问题讨论】:

  • 欢迎来到 Stack Overflow。请花时间阅读The Tour 并参考Help Center 中的材料,您可以在这里问什么以及如何问。
  • 调试器是解决此类问题的正确工具。 在询问 Stack Overflow 之前,您应该逐行逐行检查您的代码。如需更多帮助,请阅读How to debug small programs (by Eric Lippert)。至少,您应该 edit 您的问题包含一个重现您的问题的 Minimal, Complete, and Verifiable 示例,以及您在调试器中所做的观察。
  • Bar 包含源 Foo 的副本,而不是对源 Foo 的引用。 Foo 通过引用传递到函数中,但随后被复制。
  • user4581301 是对的,你应该使用foo-&gt;bar.Swap();

标签: c++ oop pass-by-reference


【解决方案1】:

您将 foo 的引用传递给 bar 的构造函数,然后将通过引用传递给 bar.foo 的 foo 分配(复制)。

您希望将其声明为对 Foo 对象的引用(或指向),而不是单独的 Foo 对象。

【讨论】:

    【解决方案2】:

    类B 的构造函数确实通过引用获取foo(参数),但立即将其复制到A 的单独实例中(特别是复制到foo 成员中); Swap 然后作用于 foo 成员,如上所述,它只是原始对象的副本。

    要使您的代码按预期运行,您甚至必须将成员 foo 设为引用(或指针):

    class Bar {
    public:
        Foo &foo;
        Bar() {
    
        }
        Bar(Foo& foo) : foo(foo) {
        }
    

    (注意我必须使用the member initialization list syntax,因为引用cannot be default-initialized and then reseated)

    【讨论】:

    • 感谢您的帮助,从 c# 到 c++ 对于 c++ 处理指针和引用的方式有点棘手。
    【解决方案3】:

    问题就在这里。

        Foo foo;
        Bar(Foo& foo) {
            this->foo = foo;   
        }
    

    即使您通过引用获取 foo 参数,您也将其分配给非引用值,这会产生副本并解决您提出的问题。解决方案的第一步也是通过引用声明您的实例字段。

        Foo& foo;
    

    但是,当您尝试分配给它时,这会导致错误。为此,我们要使用特殊的构造函数初始化语法。它与赋值基本相同,但执行构造而不是正常赋值。所以写你的构造函数如下。

        Bar(Foo& foo) : foo(foo) {}
    

    您还必须完全删除默认构造函数 Bar(),因为大多数 C++ 编译器会拒绝可能导致未初始化引用的代码。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-04
      • 2013-11-23
      • 1970-01-01
      • 2012-02-14
      • 1970-01-01
      • 1970-01-01
      • 2020-08-11
      • 1970-01-01
      相关资源
      最近更新 更多