Я нашел этот код в библиотеке рендеринга Quake 3. Существует такая функция:
void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int fogIndex, int dlightMap );'
Он вызывается в цикле еще что-то вроде этого:
R_AddDrawSurf( ( void * )poly, sh, poly->fogIndex, qfalse );
Странная часть состоит в том, что poly был объявлен как srfPoly_t *poly
. Что здесь происходит? Он srfPoly_t
объект srfPoly_t
(void *)
и затем surfaceType_t
функцию в качестве объекта surfaceType_t
.
Вот объявление для соответствующих структур:
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;
Это работает на C, но я пытаюсь реализовать что-то подобное в C++, но я получаю следующую ошибку:
Error 1 error C2664: 'int RefDef::AddDrawSurf(surfaceType_t *)' : cannot convert argument 1 from 'void *' to 'surfaceType_t *'
Казалось бы, я не могу выполнить этот тип приведения в C++, или, может быть, есть что-то еще, что я не могу понять. Я не очень хорошо знаком с C++ и хотел бы узнать, как настроить что-то подобное с этим.
Я предполагаю, что это имеет отношение к проверке типов в C++, поэтому это недопустимо. Как я могу реализовать что-то подобное в C++ безопасным способом?
Это работает в C, потому что структуры - это просто блоки памяти с каждым элементом структуры, выложенным последовательно. Это действие работает, потому что первые n
байтов структуры srfPoly_t
состоят из перечисления surfaceType_t
в этой структуре. srfPoly_t
функция пытается интерпретировать переданный srfPoly_t
как surfaceType_t
и успешно, потому что первые n
байтов аргумента являются, по сути, поверхностным surfaceType_t
. Не делайте этого без уважительной причины.
Отбрасывание из void*
не происходит автоматически в C++, как в C. Вы можете использовать reinterpret_cast
для явного броска между двумя различными типами структур:
srfPoly_t* mySrfPoly_t;
surfaceType_t* mySurfaceType = reinterpret_cast<surfaceType_t*>(mySrfPoly_t);
mySrfPoly_t.surfaceType
, а OP - после указателя на оригинал.
R_AddDrawSurf(&poly->surfaceType, ...)
способ сделатьR_AddDrawSurf(&poly->surfaceType, ...)
. Без веской причины, которую я вижу. Адрес структуры также является адресом ее первого члена, поэтому звезды совпадают. Что касается того, почему он работает в C, но не в C ++: в Cvoid*
может быть неявно преобразован в любой тип указателя, а в C ++ - нет.void*
. Он приводит указатель структуры кvoid*
.