Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Access members of other classes

10 views
Skip to first unread message

Steve Keller

unread,
Sep 14, 2022, 2:56:11 AM9/14/22
to
I find myself often in a situation where a class or struct contains
other classes/structs, both have member functions and I want to access
members of the inner class from the outer class or vice versa:

struct A {
int x;
struct B {
int y;
void bar() {
// I want to access A's member x here
}
} b;
void foo() {
// I can access B's member y here. But can I somehow
// do so using only y without the b. in front?
b.y;
}
};

I could access b.y from A:foo() as only y if I add

int &y = b.y;

in struct A {}; but that adds a pointer to A and an additional pointer
indirection with each access to b.y. But I can live with using b.y
instead while only y would be more beautiful in this case.

To access a.x from B::bar() the only clean way I've found is to add a
pointer to A in B and init it the constructor of A using 'this'. Like

struct A {
int x;
struct B {
B(A *p) : parent(p) {}
A *parent;
void bar() { parent->x; }
};
A() : b(this) {}
};

But I'd like to avoid the pointer indirection, since the offset of B
in A is known at compile time. Is that possible?

Steve

Alf P. Steinbach

unread,
Sep 14, 2022, 3:32:58 AM9/14/22
to
For suitable restricted class types you can in principle use `offsetof`,
pointer arithmetic and `reinterpret_cast`.

But consider just using inheritance:


template< class Derived >
class B {
friend Derived;
int y;
public:
void bar() {
(void) Derived::x;
}
};

class A: B<A>
{
friend class B<A>;
int x;
public:
void foo() {
(void) y;
}
};


And having said that, consider the design. The need for two classes to
mutually access each others' data members is a design smell.

- Alf

Alf P. Steinbach

unread,
Sep 14, 2022, 3:46:42 AM9/14/22
to
On 14 Sep 2022 09:32, Alf P. Steinbach wrote:
> On 14 Sep 2022 08:55, Steve Keller wrote:

Sorry that was a messed up incomplete example. Here's working full code:


#include <stdio.h>

template< class Derived >
class B {
friend Derived;
int y = 42;
public:
void bar() {
printf( "%d\n", static_cast<Derived*>( this )->x );
}
};

class A: public B<A>
{
friend class B<A>;
int x = 12345;
public:
void foo() {
printf( "%d\n", y );
}
};

auto main() -> int
{
A o;
o.foo();
o.bar();
}


If you do this (again, reconsider the design) then you can avoid much
verbosity by providing the `static_cast` via a member function e.g.
called `self`.

- Alf


Sam

unread,
Sep 14, 2022, 7:11:28 AM9/14/22
to
Steve Keller writes:

> I find myself often in a situation where a class or struct contains
> other classes/structs, both have member functions and I want to access
> members of the inner class from the outer class or vice versa:
>
> struct A {
> int x;
> struct B {
> int y;
> void bar() {
> // I want to access A's member x here
> }
> } b;
> void foo() {
> // I can access B's member y here. But can I somehow
> // do so using only y without the b. in front?
> b.y;

No. The only reason foo() can refer to x directly because x is a part of
this→.

> I could access b.y from A:foo() as only y if I add
>
> int &y = b.y;

Correct, that's how you'd do it.

> in struct A {}; but that adds a pointer to A and an additional pointer
> indirection with each access to b.y.

No, this doesn't add any pointer to any A. Additionally, you'll find out
that the resulting code will end up being identical to referencing b.y
explicitly, at least with moderate compiler optimizations enabled.

> But I can live with using b.y
> instead while only y would be more beautiful in this case.

Either way, the resulting code will be identical.

> To access a.x from B::bar() the only clean way I've found is to add a
> pointer to A in B and init it the constructor of A using 'this'. Like

Correct.

> struct A {
> int x;
> struct B {
> B(A *p) : parent(p) {}
> A *parent;
> void bar() { parent->x; }
> };
> A() : b(this) {}
> };
>
> But I'd like to avoid the pointer indirection, since the offset of B
> in A is known at compile time. Is that possible?

Of course not, because C++ does not work like that. A given instance of "B"
has nothing, whatsoever, to indicate which given instance of A it's a member
of.

A a1;
A a2;

A::B b;

b.bar();

For a plain "x" referenced in bar(), which A do you expect to be accessed,
a1 or a2 here, and why exactly? Please be specific in your answer.

Richard Damon

unread,
Sep 14, 2022, 7:44:17 AM9/14/22
to
Part of the issue is shown in a slightly more general case.

If struct A instead as

struct A {
int x;
struct B {
int y;
void bar();
} b1, b2;
void foo();
}

now, WHICH y in WHICH bx should foo access when it mentions y. your code
has a very special case.

Also if we add elsewhere a statement like:

A::B bg;

What x should bar access when it asks for x?

And even without that, how could bar in B, given just the address of the
B it is working on know where the x in the "containing" A would be, the
offset is different for b1 and b2.

Thus bar NEEDS a pointer to "its A", and foo NEEDS a pointer to the B is
wants to access, so the indirection in unavoidable, once B is made a
seperate class.

If there WILL be ONE and only one B inside of A, and that is the only
use of B, then making B a separate type is the source of the problem,
not something the language needs to help with. Just make y and bar a
member of A and that gets around the problem.

0 new messages