C++ – Representing a Many-to-Many Relationship Between Two Classes

cc++11

Let's say I have two object types, A and B. The relationship between them is many-to-many, but neither of them is the owner of the other.

Both A and B instances need to be aware of the connection; it's not just one way.

So, we can do this:

class A
{
    ...

    private: std::vector<B *> Bs;
}

class B
{
    private: std::vector<A *> As;
}

My question is: where do I put the functions to create and destroy the connections?

Should it be A::Attach(B), which then updates A::Bs and B::As vectors?

Or should it be B::Attach(A), which seems equally reasonable.

Neither of those feels right. If I stop working with the code, and come back after a week, I'm sure I won't be able to recall if I should be doing A.Attach(B) or B.Attach(A).

Perhaps it should be a function like this:

CreateConnection(A, B);

But making a global function seems undesirable also, given that it's a function specifically for working with only classes A and B.

Another question: if I run into this problem/requirement often, can I somehow make a general solution for it? Perhaps a TwoWayConnection class that I can derive from or use within classes that share this type of relationship?

What are some good ways to handle this situation… I know how to handle the one-to-many "C owns D" situation quite well, but this one is trickier.

Edit: Just to make it more explicit, this question doesn't involve ownership issues. Both A and B are owned by some other object Z, and Z takes care of all ownership issues. I'm only interested in how to create/remove the many-to-many links between A and B.

Best Answer

One way is to add a public Attach() method and also a protected AttachWithoutReciprocating() method to each class. Make A and B mutual friends so that their Attach() methods can call the other's AttachWithoutReciprocating():

A::Attach(B &b) {
    Bs.push_back(&b);
    b.AttachWithoutReciprocating(*this);
}

A::AttachWithoutReciprocating(B &b) {
    Bs.push_back(&b);
}

If you implement similar methods for B, you won't have to remember which class to call Attach() on.

I'm sure you could wrap that behavior up in a MutuallyAttachable class that both A and B inherit from, thus avoiding repeating yourself and scoring bonus points on Judgement Day. But even the unsophisticated implement-it-in-both-places approach will get the job done.

Related Topic