Приведение указателя на подкласс (C ++) - PullRequest
4 голосов
/ 05 декабря 2009

Я занимаюсь разработкой игры, и мне нужно найти способ получить значение определенного «блока карты» в игре (в формате char). У меня есть класс DisplayableObject, который заботится обо всех спрайтах, и подкласс ThreeDCubePlayer, который заботится о объекте игрока. Для простоты рендеринга / обновления всего, все DisplayableObjects хранятся в массиве с 0-й ячейкой, содержащей проигрыватель (который имеет тип ThreeDCubePlayer). ThreeDCubePlayer имеет конструктор, отличный от DisplayableObject (он принимает два дополнительных аргумента), и только ThreeDCubePlayer имеет нужные мне функции GetMap (). Итак, вот что я сделал до сих пор:

ThreeDCubePlayer* cubePlayer = &((ThreeDCubePlayer &)m_ppDisplayableObjects[0]);

char mapEntry = GetMapEntry((int)*(cubePlayer->GetMapX()), (int)*(cubePlayer->GetMapY()));

Это часть ThreeDCubeGame.cpp (функция, которая управляет картой и вводом с клавиатуры). Проблема, с которой я столкнулся, заключается в том, что обе эти строки выдают ошибку «недопустимого косвенного обращения» при компиляции. Я думал, что эта ошибка, когда я пытаюсь разыменовать что-то, что не является указателем, и я уверен, что cubePlayer выглядит как указатель ...

Кто-нибудь имеет представление о том, что я должен делать?

Ответы [ 7 ]

5 голосов
/ 05 декабря 2009

Используйте одно из типов безопасных приведений, например, dynamic_cast вместо каста в стиле C.

Если m_ppDisplayableObjects является DisplayableObject **, то это будет выглядеть примерно так:

ThreeDCubePlayer* cubePlayer = dynamic_cast<ThreeDCubePlayer*>(m_ppDisplayableObjects[0]);

if (cubePlayer != NULL)
{
    char mapEntry = GetMapEntry(cubePlayer->GetMapX(), cubePlayer->GetMapY());
}
else // Not a ThreeDCubePlayer* ...
3 голосов
/ 05 декабря 2009

Пара предложений:

Не используйте приведения в стиле C, вместо этого используйте правильные приведения в C ++. В вашем случае, когда вы приводите иерархию наследования, вы должны использовать dynamic_cast вместо применения кувалды в стиле C. Это приведет к небольшим накладным расходам времени выполнения, но также сделает весь тип объекта безопасным, поскольку он не собирается делать что-то неприятное за вашей спиной просто потому, что вы рассматриваете кусок $ deity_knows_what как ThreeDCubePlayer. Предполагая, что ваш массив m_ppDisplayableObjects действительно содержит указатели, он будет выглядеть следующим образом:

ThreeDCubePlayer *cubePlayer = dynamic_Cast<ThreeDCubePlayer *>(m_ppDisplayableObjects[0])
if (cubePlayer) {  // Important, if you don't check for 0 here you might dereference a null pointer
   ... cubePlayer->GetMapX() ...

Кроме того, если вам нужно привести результат GetMapX, у вас есть несоответствие импеданса, которое вы должны отсортировать где-нибудь еще; Я бы порекомендовал либо изменить тип возвращаемого значения GetMapX, либо параметры, передаваемые в GetMapEntry. Как правило, необходимость в диком разбрасывании является признаком проблемы проектирования - хорошо разработанный код C ++ не должен требовать большого количества приведений и особенно не большого количества приведений в стиле C.

1 голос
/ 05 декабря 2009

Имейте в виду, что в игровом приложении ситуация, в которой вы выполняете миллионы динамических трансляций за кадр, может негативно повлиять на производительность. Обычно вы найдете людей, которые занимаются другими решениями, чтобы определить, как преобразовать указатель на объект, хранящийся в контейнере, в соответствующий тип объекта, используя приведение в стиле static_cast или C, а не полагаясь на RTTI. В зависимости от количества типов объектов и других факторов, существуют различные способы сделать это, но простой метод состоит в том, чтобы просто иметь идентификатор класса перечисления и метод get для каждого из типов перечисления, который возвращает нуль, если идентификатор класса не делает ' не соответствует запрашиваемому.

1 голос
/ 05 декабря 2009

Для первой строки вы можете привести DisplayableObject к производному классу ThreeDCubePlayer, используя dynamic_cast.

ThreeDCubePlayer* cubePlayer = dynamic_cast<ThreeDCubePlayer*> (m_ppDisplayableObjects[0]);

Во второй строке вы разыменовываете все, что возвращается ThreeDCubePlayer::GetMapX(). Если эта функция не возвращает указатель (или некоторый класс с перегруженным оператором *), вы получите ошибку компиляции.

1 голос
/ 05 декабря 2009

Ваше приведение неверно, и я думаю, что вторая строка вообще не требует преобразования (зависит от того, как определены методы).

Должно быть:

ThreeDCubePlayer* cubePlayer = (ThreeDCubePlayer*)m_ppDisplayableObjects[0];

char mapEntry = GetMapEntry( cubePlayer->GetMapX(), cubePlayer->GetMapY() );

Приведение в первой строке также должно выполняться в стиле C ++, например ::1006*.

ThreeDCubePlayer* cubePlayer = static_cast<ThreeDCubePlayer*>(m_ppDisplayableObjects[0]);
0 голосов
/ 05 декабря 2009

ppDisplayableObjects - это массив или базовые указатели, не так ли? так попробуй это?

const ThreeDCubePlayer* const cubePlayer = m_ppDisplayableObjects[0]; 
char mapEntry = GetMapEntry( cubePlayer->GetMapX(), cubePlayer->GetMapY() );

GetMapX и т. Д. Должны возвращать (без знака) int? а не указатель на int? (нет негры? так без знака?)

Я бы хотел прокомментировать все остальные комментарии о кастинге, это признак того, что ваша иерархия работает не совсем корректно, но ... но если вам нужно кастовать, подумайте, какой кастинг C ++ вам понадобится использовать это полезное упражнение, это также означает, что когда вы хотите пересмотреть / укоротить свой код, все броски легче найти и удалить

ps - собери свою константу, где ты можешь и добавьте массивы и т. д. в некоторый класс владельца, возможно, в одиночный, если вы знаете, что у вас есть только один

также ИМХО ... (извините) напишите себе класс Coords, чтобы вы могли делать такие вещи, как GetMapEntry (const Coords & координаты), вместо того, чтобы получать значения x и y по отдельности, это спасет вас от замены их на неправильный путь и т. д. :)

0 голосов
/ 05 декабря 2009

Вы не дали много кода для продолжения, но я думаю, что ваша первая строка должна быть:

ThreeDCubePlayer* cubePlayer = (ThreeDCubePlayer *) m_ppDisplayableObjects[0]);

Нам нужно увидеть объявление GetMapX (), чтобы узнать о второй строке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...