Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C Inheritance with Unions

Tags:

I was reading somewhere about how some object oriented features can be implemented in C, and it has proven fairly useful. In specific, I have been toying with the idea of inheritance. Here is an example:

typedef struct Circle{
     int rad, x, y;
     //Other things...
} Circle;

typedef struct Entity{
    Circle body;
    //Entity-specific items...
} Entity;

This is simple, but it allows for something sneaky. A pointer to an Entity is ALSO a pointer to a Circle because the first element of an Entity is always a Circle. With this idea, we can construct the following function:

int checkCircleCollision(Circle* one, Circle* two);

And call it as such:

Entity* myentity = createEntity(/* Things specific to my entity */);
Entity* myotherentity = createEntity(/* Different things */);
//Did they collide?
if (checkCircleCollision(myentity, myotherentity)){
    /* ... */
}

This is wonderful, but I ran into a problem. What if I wanted some of my Entities to be rectangles, too? I have a solution, but I'd like confirmation that it will always work, no matter the compiler. My knowledge on unions is very limited.

//Circle defined as above...
typedef struct Rectangle{
    int x, y, w, h;
    //Other things...
} Rectangle;

int checkRectangleCollision(Rectangle* one, Rectangle* two);
int checkRectangleCircleCollision(Rectangle* rect, Circle* circ);

typedef struct Entity{
     union{
         Rectangle rect;
         Circle circ;
     } shape;
     int type;
     //Entity things...
}

Is it now completely safe to assume that the first element of an Entity is either a Rectangle or a Circle, depending on its initialization? Furthermore, could it be used in any of the three functions described above? Bonus points for relevant quotes from the standard. To be perfectly clear, I'd like to do this:

Entity* rectentity = createEntity(RECTANGLE, /* width/height/etc */);
Entity* circentity = createEntity(CIRCLE, /* rad/x/y/etc */ );
if (checkRectangleCircleCollision(rectentity, circentity)){
     /* ... */
}