在 C++ 中的不同 class 中访问 class 的成员

Access members of a class within a different class in c++

我正在尝试理解使用 C++ 的面向对象编程。以下是一个最小的例子,结果不是我天真的期望:

#include <iostream>

class B {
public:
      B (int val) : val(val) {;}

      int get_val() { return val; }
      int set_val(int a) { val = a; }

private:
      int val;
};

class A {
public:
      A (B b) : b(b) {;}
      B get_b() { return b; }

private:
      B b;
};

int main(){
    B b_main(5);
    std::cout << b_main.get_val() << std::endl; // Prints 5, which makes sense

    A a_main(b_main);
    std::cout << a_main.get_b().get_val() << std::endl; // Prints 5, which makes sense

    a_main.get_b().set_val(2);
    std::cout << a_main.get_b().get_val() << std::endl; // Why does this not print 2?

    return 0;
}

最后一个 cout 语句对我来说没有意义。在倒数第二行中,我将对象的值设置为 2,那么为什么不打印 2?查看 Stack Exchange 上的一些类似问题,我发现了一些让 A 和 B 成为彼此朋友的建议。我尝试在 class B 中添加 friend class A 并在 class A 中添加 friend class B,但这没有用。在我的理解中,添加 friend 语句应该是不必要的,因为我在 class A 中有 get_b() 方法。我发现了一些尝试通过引用 A 的构造函数传递类型 B 的对象的建议: A (B& b) : b(b) {;} 但这也不起作用。

任何人都可以向我解释为什么程序没有产生预期的结果以及如何获得预期的结果(即最后一个 cout 语句打印 2)?

注意:我还尝试了以下内容。我将 class A 的私有变量 b 设为 public:

#include <iostream>

class B {
public:
    B (int val) : val(val) {;}
    int get_val() { return val; }
    int set_val(int a) { val = a; }

private:
    int val;
};

class A {
public:
  A (B b) : b(b) {;}
  B b; // This is now public
  //B get_b() { return b; } // This is no longer needed

private:
};


int main(){
    B bmain(5);
    std::cout << bmain.get_val() << std::endl;

    A amain(bmain);
    std::cout << amain.b.get_val() << std::endl;

    amain.b.set_val(2);
    std::cout << amain.b.get_val() << std::endl; // Works!

    return 0;
}

现在我得到了想要的结果。与第一个代码片段相比,这是代码的实现方式吗?我想要第一个代码片段中的 get_b() 方法,但如果这不是解决此问题的正确方法,请告诉我。

get_b returns 是您的私有变量 b 的副本,而不是实际变量。如果您希望能够访问它,则需要 return 对 b 的引用,以便可以操纵 returned 值。您的 get_b 定义应如下所示:

B& get_b() { return b; }

如果那是您希望做的。然而,这通常不是理想的解决方案。如果你打算主动改变 b 的值,你应该写一个 set_b 函数来操作变量。如果你真的经常使用变量,读取和写入值,你应该保留它 public 以便快速访问。

In the second to last line, I set the value of the object to be 2, so why does this not print 2?

因为您使用get_b() 方法return a_mainB 对象的 副本。发生的事情是 a_main 中的 b 变量被复制,即 class B 的另一个对象,与 b 成员相同,被创建,并且 return发送给来电者。然后,修改新的 B 对象。但它与a_main中的原始b没有联系。这与可见性和成员访问权限无关。

然而,在第二个示例中,您在a_main中公开了b成员,并直接对该对象进行操作,而没有复制它,因此结果成功。 public 修饰符改变的是它允许您直接访问 b 对象,因此效果。

I found some suggestions to try passing the object of type B in by reference to the constructor of A: A (B& b) : b(b) {;} but this did not work either.

那是行不通的。当您这样做时会发生什么,A::b 是使用通过引用传递的值 true 进行初始化的。但是引用 只会导致没有额外的 b 副本传递给正在制作的构造函数 。此引用不会在传递给构造函数的 bA::b 之间创建 link。它在另一端,可以这么说。

顺便说一句,A (B& b) : b(b) {;} c'tor 参数名称与成员名称相同是一种不好的做法。将它们命名为相似的是个好主意,但仍然添加例如下划线:A (B& _b) : b(_b) {;}

如果您想在第一个片段中获得相同的结果,return 引用b,如下所示:

  B& get_b() { return b; }

不过,这是不可取的,因为您暴露了 class A 的私有成员只是为了允许 A 的客户端修改该成员的某个 属性 .最好在 A 中提供一种方法来设置 A::bval 属性 而无需完全访问 A::b.

肯定看到这个:What's the difference between passing by reference vs. passing by value?

也许这样:Java and C++ pass by value and pass by reference

因为我觉得你来自 Java 并且默认情况下期望 C++ 中的按引用传递。

为了完整起见,您可以将此问题作为 C 编程问题来解决,而不是使用 C++ 编程中所有花哨的引用。当你从 a_main 得到 b_main 时, returned 对象不占用相同的内存地址。

#include <iostream>

class B {

public:

  B (int val) : val(val) {;}

  int get_val() { return val; }
  int set_val(int a) { val = a; }

private:

  int val;

};

class A {

public:

  A (B b) : b(b) {;}
  B get_b() { return b; }

private:

  B b;

};


int main(){

  B b_main(5);
  B* addrb = &b_main;
   std::cout << b_main.get_val() << std::endl; // Prints 5, which makes sense
    std::cout<<"Address of b_main: "<<addrb<<std::endl;
  A a_main(b_main);
  B bt = a_main.get_b();
  addrb = &(bt);
  std::cout << a_main.get_b().get_val() << std::endl; // Prints 5, which makes sense
    std::cout<<"Address of a_main.get_b(): "<<addrb<<std::endl;
  a_main.get_b().set_val(2);
  std::cout << a_main.get_b().get_val() << std::endl; // Why does this not print 2?

  return 0;

}

注意新 cout 语句的地址差异。解决此问题的一种方法是 return 指针而不是 b 本身。即

#include <iostream>

class B {

public:

  B (int val) : val(val) {;}

  int get_val() { return val; }
  int set_val(int a) { val = a; }

private:

  int val;

};

class A {

public:

  A (B b) : b(b) {;}
  B* get_b() { return &b; }

private:

  B b;

};


int main(){

  B b_main(5);
  //B* addrb = &b_main;
   std::cout << b_main.get_val() << std::endl; // Prints 5, which makes sense
    //std::cout<<"Address of b_main: "<<addrb<<std::endl;
  A a_main(b_main);
  //B bt = a_main.get_b();
  //addrb = &(bt);
  std::cout << a_main.get_b()->get_val() << std::endl; // Prints 5, which makes sense
    //std::cout<<"Address of a_main.get_b(): "<<addrb<<std::endl;
  a_main.get_b()->set_val(2);
  std::cout << a_main.get_b()->get_val() << std::endl; // Why does this not print 2?

  return 0;

}