I have a class C, which has a vector of objects of class E. Objects of class E will often 'link' with other objects of class E - if two objects of class E are linked then each object will contain the unique ID of the other object.
I'm wondering where its best, from a design perspective, to put the 'linkage':
1. The function is a member function of E. In this case, the function would be called on one object (E1) but it would receive as a parameter the ID of the object (E2) it was linking with. In this case, E1 would need access to object of class C in order to access E2 (in order to add E1's unique ID to E2).
2. The function is a member function of C. In this case, the function would take in the IDs of E1 and E2 and then add the IDs to each object (i.e. E1 adds E2's ID and E2 adds E1's ID).
On the one hand, I can see that (1) is nice because it seems sensible on some level that the linkage function should belong to E. On the other hand, (2) seems good because generally it seems a bad idea for child objects to have access to their parent objects.
You seem to be leaning towards 2) as the solution which avoids the problems of back-pointing to the container class C. As long as there is no reason for C to not be able to have the methods, why not put them in C? I wasn't sure which class handles the logic of deciding when to link the instances of the E class though - does this ALSO go in the C class? If the logic for when to link goes in C, then C has even more reason to do the "linkage". Below in class C, I declared two different link methods as I wasn't sure if you would have the first E object in some cases, and not just the id for E1. I chose to put a method link in the E class to set the id. I haven't really put much into this, so take it for what it's worth - just my opinion without agonizing over it. I'm assuming that it's not hard to put the logic for decision-making in C. If it is hard, it's ok to use back-pointers, although it's a lot of potential baggage unless you get the back-pointer only when you need it. And even then, it seems silly to get a back-pointer, then simply get the vector, and then put all the same methods in E. Just my opinion. But I can think of cases when you might have to put all the logic and the linkage itself in E and not in C. If E was something that is hard for C to "understand", for example. If the decision is complex, then the decision-making could be put in E, and still, the actual linkage operation in C. I think 2) wins either way.
class C
{
// Member methods
public:
// I'm skipping many of the methods I mention below.
// createVector(), destroyVector(), append, delete, etc..
void link(E e1, IDTYPE id2)
{
E &otherE = findE(id2);
otherE.link(e1.myId);
}
void link(IDTYPE id1, IDTYPE id2)
{
E &myE = findE(id1);
E &otherE = findE(id2);
myE.link(id2);
otherE.link(id1);
}
E &findE(IDTYPE id)
{
// Look up id by iterating over vector's members until a match is
// found
// and return object E.
// return anE;
}
// Member data
protected:
vector ve<E>; // I didn't declare this class correctly, only schematicly.
};
class E
{
// Member methods
public:
// NOTE: The below methods would be more cumbersome than if the
// "linkage" was simply
// implemented in the containing class C. (Not to mention getVector,
// vector.findE(), etc..
// as I indicate below. So these methods are NOT needed if "linkage" is
// implemented in C.
E() { pMyContainer = NULL; }
E(C *pContainer) { pMyContainer = pContainer; }
SetContainer(C *pContainer) { pMyContainer = pContainer; }
// Likely, E would also need some sort of getVector(), vector.findE(), etc..
void link(id)
{
otherId = id;
}
// Member data
protected:
IDTYPE myId;
IDTYPE otherId;
C *pMyContainer; // NOTE: This member is NOT needed if "linkage" is
// implemented in C.
};