Composition & member access

Hello all!

I have a question regarding composition and accessing members "deep" inside the composed structure. For example;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class A
{
private:
   int m_myInt;
public:
   int myInt() const {return this->m_myInt;};
   void myInt(int newInt) {this->m_myInt = newInt;};
};

class B
{
private: 
   A m_a;
public:
   //???
};


Now, from somwhere I have access to an object of type B where I want to update the A::m_myInt. How would you do this without "breaking" the whole purpose of private/public members?

1
2
B myB;
myB.m_a.myInt(3); // Not allowed, and not desireable 


I thought about implementing access through functons kind of like;
 
A & B::a() {return this->m_a;};

 
myB.a().myInt(3); 

but I'm worried that this exposes my B::m_a-object too much. This would allow
 
myB.a() = A();
, right?

The following is a more desireable way of acces, but doesn't work for updating;
 
A const & B::a() {return this->m_a;};

 
myB.a().myInt(3);  //Disallowed? myInt(int) is non-const. 


What about this? Is this a good way of doing it?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class A
{
private:
   int m_myInt;
public:
   int myInt() const {return this->m_myInt;};
   void myInt(int newInt) {this->m_myInt = newInt;};
};

class B
{
private: 
   A m_a;
public:
   A const & a() const {return this->m_a;};
   void a(A const & newA) {this->m_a = newA;};
};


1
2
3
4
B myB;
A newA = myB.a();
newA.myInt(3);
myB.a(newA);


Looks kind of ugly to me, but I guess it works? It would lead to a lot of data shuffling in case of larger sub-components.I would really like to do the following without exposing my components so much:

1
2
B myB;
myB.a().myInt(3);


Can it be done?

Thanks : )

//Bobruisk






How does this look
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class A
{
private:
    int m_myInt;
public:
    int myInt() const {return this->m_myInt;}
    void myInt(int newInt) {this->m_myInt = newInt;}
};

class B
{
private:
    A m_a;
public:
    void myInt(int newInt) {m_a.myInt(newInt);}
};

// else where
{
    B myB;
    myB.myInt(3);
}
Sure that works, but it gets really annoying when there are multiple layers of classes like this. Also it forces me to implement a lot of functionality that is really A-related in B.
> How would you do this without "breaking" the whole purpose of private/public members?
All your examples break encapsulation
¿Is there a difference between myB.a().myInt(3); and myB.m_a.myInt(3); ?
Yeah they do. I was looking for some other way of doing this. Is Santosh Reddy's example the common solution?
Is there a difference between myB.a().myInt(3); and myB.m_a.myInt(3); ?
Yes, they are different, the second appraoch exposes the class A is user, and first one does not.

You want to access class A, from class B's user. This aproach itself laysdown the requirment that user of class B is aware (or has be aware) of class A (at-least the existanse of class A).

Now, if class A can be live with out class B, then you initial approach is better, like objB.setA(objA);

If the class A is only used by class B, and has no meaning with out side class B, then objB.setInt(3); is better approach;
¿How can you say that myB.a()does not expose class A?
You can do whatever you want with that the member.


@OP: Check out `Law of Demeter'

there are functions more interesting than getters/setters
@ne555: you are right, I am sorry.... I might have been half asleep.
@ne555 The difference is not so much in exposing the member for use, but opening it up to modification.

e.g
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class A {
public:
 string my_string() { return my_string; }
 void set_my_string(string new_value) { my_string = new_value; }

private:
 string my_string;
};

class B {
public:
 X my_bad_a;
 
 const A& my_a() const { return my_a; } 

private:
A my_a;
};

int main() {

 B my_b;
 
 A some_new_a;

 my_b.my_a().set_my_string("a");

 my_b.my_bad_a = some_new_a; // Bad! 
 my_b.my_a().set_my_string("a');


 return 0;
} 



That all being said. @bob your problem seems to be more design than code implementation. Something accessing B should have no requirement to modify a member of A.
Last edited on
I don't understand what you are trying to say with that code snip.
The line;
 
my_b.my_a().set_my_string("a'); 

, can you even do that? B::my_a() returns a reference to a const A. You can't call set_my_string("a") on a const object.

@ne555 Ahh yea, I wasn't thinking properly when I wrote that.
@Bobruisk yea you are correct, but you can override that (not recommended).

Actually either case is going to be bad. Because you have the ability to modify the member that is returned. Both attempts actually break encapsulation

So you can end up with code like:
1
2
3
4
5
6
7
8
9
	Derived derived;
	derived.parent().set_name("good name");
	cout << "Expected: good name | Actual: " << derived.parent().name() << endl;

	Parent bad_parent;
	bad_parent.set_name("bad_name");
//	derived.parent_ = bad_parent; OR
	derived.parent() = bad_parent;
	cout << "Expected: good name | Actual: " << derived.parent().name() << endl;


This overall does appear to be a fault in the design of the solution, more so than how do I code this solution. Perhaps your derived class should inherit from the parent instead of holding an instance of it?
Last edited on
Topic archived. No new replies allowed.