Reputation: 1233
I found this code in the rendering library for Quake 3. There is this function:
void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int fogIndex, int dlightMap );`
It is being called in a loop somehwere else like this:
R_AddDrawSurf( ( void * )poly, sh, poly->fogIndex, qfalse );
The weird part is that poly was declared as srfPoly_t *poly
. What is going on
here? It is casting a srfPoly_t
object to (void *)
and then entering the
function as a surfaceType_t
object.
Here are the declaration for the relevant structs:
typedef enum {
SF_BAD,
SF_SKIP, // ignore
SF_FACE,
SF_GRID,
SF_TRIANGLES,
SF_POLY,
SF_MD3,
SF_MD4,
SF_FLARE,
SF_ENTITY, // beams, rails, lightning, etc that can be determined by entity
SF_DISPLAY_LIST,
SF_NUM_SURFACE_TYPES,
SF_MAX = 0x7fffffff // ensures that sizeof( surfaceType_t ) == sizeof( int )
} surfaceType_t;
typedef struct srfPoly_s {
surfaceType_t surfaceType;
qhandle_t hShader;
int fogIndex;
int numVerts;
polyVert_t *verts;
} srfPoly_t;
This is working in C, but I am trying to implement something similar in C++, but I get the following error:
Error 1 error C2664: 'int RefDef::AddDrawSurf(surfaceType_t *)' : cannot convert argument 1 from 'void *' to 'surfaceType_t *'
It would appear I cannot perform this type of cast in C++, or maybe there is something else I am unable to understand. I am not very familiar with C++ and would love to figure out how to set up something similar using it.
I am assuming this has something to do with type checking in C++, so it is not allowed. How can I implement something similar in C++ in a safe way?
Upvotes: 1
Views: 4467
Reputation: 709
This works in C because structs are simply blocks of memory with each element in the struct laid out consecutively. This cast works because the first n
bytes of a srfPoly_t
struct consist of the surfaceType_t
enum within that struct. The called function tries to interpret the passed-in srfPoly_t
as a surfaceType_t
, and succeeds because the first n
bytes of the argument are, in fact, a surfaceType_t
. Do not do this without a very good reason.
Casts from void*
's do not automatically occur in C++ as they do in C. You can use reinterpret_cast
to explicitly cast between two different types of structs:
srfPoly_t* mySrfPoly_t;
surfaceType_t* mySurfaceType = reinterpret_cast<surfaceType_t*>(mySrfPoly_t);
Upvotes: 6