指向同一实例在不同类中使用

huangapple go评论78阅读模式
英文:

Pointer to the same instance used in a different class

问题

在这个测试中,值是不同的,不是同一个实例,我想在*From `test()`*中得到55的结果。怎么做到这一点?
英文:

How to solve this situation: I have three classes, to call them A, B and C. In C I have members of A and B. How do I set a pointer in B to have the same instance from C to A ?

#include <stdio.h>

class A {
public:
  int x; // no init, random to can test
  A() {
    printf("From A, x=%d\n", x);
  }
  void getP(A *ptr) {
    ptr = this;
  }
};

class B {
public:
  A *a;
  B() {
    a->getP(a);
    printf("From B, x=%d\n", a->x);
  }
  void test() {
    printf("From test(), x=%d\n", a->x);
  }
};

class C {
public:
  A a; B b;
  C() {
    a.x=55;
    printf("From C, x=%d\n", a.x);
    b.test();
  }
};

int main () {
  C c;

  return 0;
}

In this test, the values are different, is not the same instance, I want to have 55 result in From test() . How to make this?

答案1

得分: 3

**代码中的问题:**

您当前的代码在`B`构造函数的这一行存在未定义行为([undefined behavior][1]):

a->getP(a);

这是因为在这一点上`a`尚未初始化,因此使用`->`对其进行解引用是未定义行为。

此外,`A::getP(A *ptr)`通过值获取`ptr`,因此它不会更新来自调用者的指针。
为了实现这一点,您需要通过引用获取它(`void getP(A * & ptr)`)。但实际上,这不再需要 - 请看下文。

**解决方案:**

为了实现您想要的效果,您可以在`B`的构造函数中添加一个`A*`参数,用于初始化`B::a`成员。
然后,在从`C`的构造函数中构造`B`时,传递`C::a`成员的地址。

现在不再需要`A::getP`。

以下是您的完整示例,带有这些修改。
(修改部分用“VVVVV”标记)。

#include <stdio.h>

class A {
public:
int x{ 0 };
A() {
printf("来自A,x=%d\n", x);
}
};

class B {
public:
A* a;
//----VVVVVV----VVVV---
B(A * a_) : a(a_) {
printf("来自B,x=%d\n", a->x);
}
void test() {
printf("从test(),x=%d\n", a->x);
}
};

class C {
public:
A a; B b;
//--------VVVVV--
C() : b(&a) {
a.x = 55;
printf("来自C,x=%d\n", a.x);
b.test();
}
};

int main() {
C c;
return 0;
}

输出:

来自A,x=0
来自B,x=0
来自C,x=55
从test(),x=55

请注意,有未初始化的数据是不好的实践,因此我将`A::x`初始化为0。

[1]:https://en.wikipedia.org/wiki/Undefined_behavior
英文:

Issues in you code:

Your current code has UB (undefined behavior) in this line in B constructor:

a-&gt;getP(a);

This is because a is not initialized at this point and therefore it is UB to dereference it (with -&gt;).

In addition, A::getP(A *ptr) is getting ptr by value, and therefore it does not update the pointer from the caller.
In order to do so you need to get it by reference (void getP(A * &amp; ptr)). However it is not needed at all - see below.

Solution:

In order to achieve what you want, you can add a A* parameter to the constructor of B, that will be used to initialized B::a member.
Then pass the address of C::a member, when B is constructed from C's constructor.

There is also no need for A::getP anymore.

Below is your complete example with this modification.
(the changes are marked with "VVVV").

#include &lt;stdio.h&gt;

class A {
public:
    int x{ 0 };
    A() {
        printf(&quot;From A, x=%d\n&quot;, x);
    }
};

class B {
public:
    A* a;
//----VVVVVV----VVVV---
    B(A * a_) : a(a_) {
        printf(&quot;From B, x=%d\n&quot;, a-&gt;x);
    }
    void test() {
        printf(&quot;From test(), x=%d\n&quot;, a-&gt;x);
    }
};

class C {
public:
    A a; B b;
//--------VVVVV--
    C() : b(&amp;a) {
        a.x = 55;
        printf(&quot;From C, x=%d\n&quot;, a.x);
        b.test();
    }
};

int main() {
    C c;
    return 0;
}

Output:

From A, x=0
From B, x=0
From C, x=55
From test(), x=55

Note that it's not a good practice to have uninitialized data, and therefore I initialized A::x to 0.

huangapple
  • 本文由 发表于 2023年4月13日 18:01:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/76004139.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定