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 {returnthis->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() {returnthis->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() {returnthis->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 {returnthis->m_myInt;};
void myInt(int newInt) {this->m_myInt = newInt;};
};
class B
{
private:
A m_a;
public:
A const & a() const {returnthis->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:
class A
{
private:
int m_myInt;
public:
int myInt() const {returnthis->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); ?
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;
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.
@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?