Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When classes want to couple

I am having an issue with 2 classes that were once nicely separated, but now they want to couple.

Without getting too much into the specifics of the problem, here it is:

I used to have a class Triangle that contained 3 space-position vertices.

class Triangle
{
    Vertex a,b,c ; // vertices a, b and c
} ;

There were many Triangle instances in the program, so each had retained their own copy of their vertices. Member functions such as getArea(), getCentroid() etc were written in class Triangle, and since each Triangle instance had copies of Vertex a, b and c, finding the area or centroid had no dependence on other classes. As it should be!

Then I wanted to move to a vertex-array/index buffer style representation, for other reasons. This means all vertices are stored in a single array located in a Scene object, and each Triangle retains only REFERENCES to the vertices in Scene, not copies of the vertices themselves. At first, I tried switching out for pointers:

class Scene
{
    std::vector<Vertex> masterVertexList ;
} ;

class Triangle
{
    Vertex *a,*b,*c ; // vertices a, b and c are pointers
    // into the Scene object's master vertex list
} ;

(In case you're wondering about the benefits, I did it for reasons mostly to do with triangles that share vertices. If *a moves then all triangles that use that vertex are updated automatically).

This would have been a really good solution! But it didn't work reliably, because std::vector invalidates pointers, and I was using a std::vector for the master vertex list in class Scene.

So I had to use integers:

class Triangle
{
    int a,b,c ; // integer index values
    // into the Scene object's master vertex list
} ;

But now I have this new coupling problem: to find its own area or centroid, class Triangle needs access to class Scene where before it did not. It seems like I've fsck`d something up, but not really.

WWYD?

like image 927
bobobobo Avatar asked Sep 06 '10 16:09

bobobobo


3 Answers

Why not just have the vector in Scene just store pointers too?

std::vector<Vertex *> masterVertexList;

That way, Triangle can continue to use Vertex *'s and all you have to do is make sure that the pointers are deleted in Scene's destructor.

like image 136
Nathan Osman Avatar answered Sep 29 '22 01:09

Nathan Osman


You could pass the vector to the triangle in its constructor so it can keep a reference to the vector. Then it does not need to access or know about a Scene.

typedef std::vector<Vertex> VertexContainer;

class Scene
{
    VertexContainer  masterVertexList ;  
} ;  

class Triangle  
{  
    // A references to the vertices contained in Scene.
    // A triangle no longer needs to know anything about a scene
    VertexContainer&   vertexListRef;

    // index into vertexListRef of the triangles points.
    VertexContainer::size_type  a;
    VertexContainer::size_type  b;
    VertexContainer::size_type  c;  

    public:
        Triangle(VertexContainer&           masterVertexList,
                 VertexContainer::size_type x,
                 VertexContainer::size_type y,
                 VertexContainer::size_type z)
            :vertexListRef(masterVertexList)
            ,a(x),b(y),c(z)
        {}
};
like image 34
Martin York Avatar answered Sep 29 '22 02:09

Martin York


It seems to me that your Triangle really does depend on your Scene (since its vertices are all members of that particular scene), so there is no shame in making the object do so. In fact, I would probably give the Triangle an obligatory Scene* member.

like image 25
Colin Fine Avatar answered Sep 29 '22 02:09

Colin Fine