Let's say I have three classes, Solid
, Face
, and Edge
that are defined as follows:
class Solid{
public:
// perform an action on a single edge.
void addFillet(int edgeNum);
// perform an action on a single face
void addBore(int faceNum);
// perform an action on all faces and edges
void move(Pos newPosition);
private:
std::vector<Edge*> edges;
std::vector<Face*> faces;
};
class Face{
public:
// will modify a subset of edges
virtual void changeHeight(int newHeight) = 0;
private:
int myNum;
std::vector<Edge> edges;
}
class Edge{
public:
virtual void changeLength(int newLength) = 0;
private:
int myNum;
int length;
}
in this example, Solid
manages a 'superset' of Edge
s. Each Face
that Solid
manages will have a 'sub-set' of Solid.edges
. Further, any two Solid.faces
may have a common Edge
.
My question: are there any design patterns or general object-oriented principles for dealing with situations like this? How can I manage the relationship between Solid.edges
and Face.edges
? More specifically
There are many ways of managing these sorts of relationships but if you want efficiency and you want to share vertices between edges and share edges between faces then I suggest your
Solid
should own a complete list ofVertex
andEdges
.Then
Edge
has some sort of non-owning reference to its vertices andFace
has some sort of non-owning reference to its edges. Those non-owning references could be something like a pointer but you then have to be careful you don't invalidate those pointers by reallocating the main list of vertices or edges. It is safer if you store indices instead. But that does mean you have to refer toSolid
to find out what a vertex/edge index refers to:Live demo.
An alternative is to use
std::shared_ptr
forEdge
andVertex
but then you have to pay for the dynamic memory allocation and poorer data locality.It is tempting to store a back-reference to
Solid
insideFace
andEdge
for better encapsulation. You could do that but then thevector
ofFace
andEdge
effectively contain a lot of duplicate pointers. If that sort of encapsulation is important to you I suggest you create some sort of wrapper classes for working with edges and faces that contain the raw edge/face object and also a back-reference to theSolid
.