访问c ++

时间:2016-02-21 18:57:11

标签: c++ oop object member

我试图用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成为彼此的朋友。我尝试在B类中添加friend class A,在A类中添加friend class B,但这不起作用。根据我的理解,添加友元语句应该是不必要的,因为我在类A中有get_b()方法。我发现了一些建议,试图通过引用A的构造函数来传递类型B的对象:{{1}但这也不起作用。

有人可以向我解释为什么程序没有产生预期的结果,以及如何获得所需的结果(也就是说,最后一个cout语句打印2)?

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

A (B& b) : b(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 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; } 方法,但如果这不是正确的解决方法,请告诉我。

3 个答案:

答案 0 :(得分:3)

  

在倒数第二行,我将对象的值设置为2,那为什么不打印2?

因为您使用B方法在a_main中返回get_b()对象的副本。发生的情况是复制b中的a_main变量,即创建与B成员相同的另一个类b的对象,并返回给调用者。然后,修改新的B对象。但它与b中的原始a_main无关。这与可见性和成员访问几乎没有关系。

但是,在第二个示例中,您在b中公开a_main成员并直接对该对象进行操作而不复制它,从而获得成功结果。 public修饰符更改的内容是它允许您直接访问b对象,从而产生效果。

  

我找到了一些建议,尝试通过引用A A (B& b) : b(b) {;}的构造函数来传递类型B的对象,但这也不起作用。

那不会起作用。当你这样做时会发生的是A::b使用引用传递的值初始化,为true。但是引用只会导致没有传递给正在构造函数的b的附加副本。此引用不会在传递给构造函数的bA::b之间创建链接。它可以说是另一端。

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

如果您想在第一个代码段中获得相同的结果,请将引用返回b,如下所示:

  B& get_b() { return b; }

但是,这是不可取的,因为您公开了类A的私有成员只是为了允许A的客户端修改该成员的某个属性。最好在A中提供一种方法来设置val的{​​{1}}属性,而不必提供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 ++中默认使用pass-by-reference。

答案 1 :(得分:1)

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

B& get_b() { return b; }

如果这是你期望的。但是,这通常不是理想的解决方案。如果您要主动更改b的值,则应编写set_b函数来操作变量。如果你真的正在使用变量,读取和写入值,你应该公开它以便快速访问。

答案 2 :(得分:0)

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

#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语句的地址差异。解决这个问题的一种方法是返回指针而不是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;

}