If I have multiple structs which have a common method like this:
typedef struct s sphere;
typedef struct s{
point3 center;
double radius;
bool (*hit)(sphere, const ray*, double, double, hit_record*);
} sphere;
typedef struct b box;
typedef struct b{
point3 center;
double radius;
bool (*hit)(box, const ray*, double, double, hit_record*);
} box;
Is it possible for me to create some type of array such that it can store both of these structs and loop through it calling the method like this:
objects shapes[50]; // Where objects is something that can let shapes hold both structs
//Pretend shapes has a mixture of Boxes and Spheres
int number_of_shapes = 20;
for (int i = 0; i < number_of_shapes;i ){
if shapes[i].hit(shapes[i], r, t, t, red) { //random variables
;// do something
}
}
I just started learning c yesterday so I am not really sure what to do. I tried using void pointers but that also failed miserably.
CodePudding user response:
Void pointers are the right way to do that, but it requires that your objects are persistent in memory, because an array of pointers won't retain them. This would be possible, for instance, if you allocate each object using malloc.
A good way to do that with a lot of objects, would be to use two helper functions : one to allocate an instance and add a pointer in the array, another to remove that pointer from the array and free the structure it points to. But this supposes managing a dynamic sized array, which is another question.
Another solution, maybe simpler, would be to have two arrays of structures (not pointers), one for each type, just to maintain the objects alive, and an array of void pointers (pointing to indices of these two arrays) to mix them.
CodePudding user response:
Here is a rough cut of how you might achieve your objective...
enum { BOX, SPHERE } types;
typedef struct sphere {
point3 center;
double radius;
} sphere_t;
typedef struct box {
point3 center;
double len, wid, dpth;
double rotX, rotY, rotZ;
} box_t;
typedef object {
int type;
union {
sphere_t sphere;
box_t box;
};
} object_t;
int main() {
object_t objs[ 50 ];
/* ... */
for( int i = 0; i < numObjs; i )
switch( objs[ i ].type ) {
case BOX:
hndlr_Box( objs[i].box );
break;
case SPHERE:
hndlr_Sphere( objs[i].sphere );
break;
/* ... */
}
}
Looking back at that, it might be even better to use a linked list of objects instead of an array.
AND, each object instance in the array will consume as much memory as is required for the largest of the union. It may be better to use pointers to separately allocated blocks, each storing only its particular attributes.