проблемы с доступом к производному классу в массиве - PullRequest
1 голос
/ 05 февраля 2011
class BaseObj
{
public:
    int position;
};

class EnemyObj: public BaseObj
{
public:
    int quantity;
};

class PlayerObj: public BaseObj
{
public:
    int lives;
};

int main()
{
    BaseObj* myObjs[3];

    BaseObj* b = new BaseObj();
    b->position = 1;
    myObjs[0] = b;

    EnemyObj* e = new EnemyObj();
    e->position = 2;
    e->quantity = 5;
    myObjs[1] = e;

    PlayerObj* p = new PlayerObj();
    p->position = 3;
    p->lives = 2;
    myObjs[2] = p;

    myObjs[2]->lives = 2;  // error is here
    return 0;
}

моя проблема в том, что я хочу иметь массив всех своих игровых объектов, чтобы я мог собрать их все вместе, но когда я пытаюсь получить доступ к myObjs [2] -> жизни, я не могу этого сделать.Это ошибка, которую я получаю:

error C2039: 'lives' : is not a member of 'BaseObj'

Ответы [ 5 ]

3 голосов
/ 05 февраля 2011

C ++ - это статически типизированный язык, и это означает, что каждая переменная имеет определенный тип.Ваш массив содержит указатели на BaseObj, и это означает, что компилятор разрешит доступ только к элементам, определенным в этом классе.

Вы можете сказать компилятору, что один из этих указателей действительно указывает на более конкретный (т.е. производный) экземпляр класса двумя способами:

  1. dynamic_cast<PlayerObj*>(p)

    Это выражение будет возвращать указатель на PlayerObj, если действительно p указывает на экземплярэтого класса (или экземпляру класса, производного от PlayerObj).Если это не так, однако возвращаемый указатель будет нулевым указателем, даже если p не был нулевым.

    Чтобы иметь возможность использовать dynamic_cast для базового -> производного преобразования, вы должны быть уверены, что Информация о типе времени выполнения (RTTI) была включена, если она не используется по умолчанию для вашего компилятора и что ваш базовый класс является "полиморфным типом", то есть он должен иметь хотя бы один виртуальный метод.

  2. static_cast<PlayerObj*>(p)

    Это делает то же преобразование, однако, если p не указывает на экземпляр PlayerObj или на класс, производный от PlayerObj, тогдавы входите в землю с неопределенным поведением, точно так же, как когда вы пишете из массива или используете объект после того, как вы delete d.Это может означать сбой программы, сумасшедшее поведение, демоны, летящие у вас из носа, или даже хуже (например, все кажется, что все работает, и сбой произойдет через миллион выполненных инструкций позже.)решение, используемое во многих программах на C ++, состоит в том, чтобы использовать только static_cast, но в конечном итоге сначала проверять тип указанного экземпляра, имея элемент данных типа (например, enum) в базовом классе.Это означает, что вы в основном строите свой собственный RTTI вместо того, чтобы использовать тот, который предоставлен компилятором.

2 голосов
/ 05 февраля 2011

dynamic_cast ваш друг:

#include <iostream>
#include <memory>

class BaseObj {
public:
    BaseObj() : position(-1) {
    }

    virtual ~BaseObj() {
    }

    int position;
};

class EnemyObj : public BaseObj {
public:
    EnemyObj() : quantity(0) {
    }

    virtual ~EnemyObj() {
    }

    int quantity;
};

class PlayerObj : public BaseObj {
public:
    PlayerObj() : lives(9) {
    }

    virtual ~PlayerObj() {
    }

    int lives;
};

int main() {
    BaseObj* myObjs[3];

    BaseObj* b = new BaseObj();

    b->position = 1;
    myObjs[0] = b;

    EnemyObj* e = new EnemyObj();
    e->position = 2;
    e->quantity = 5;
    myObjs[1] = e;

    PlayerObj* p = new PlayerObj();
    p->position = 3;
    p->lives = 2;
    myObjs[2] = p;

    if (PlayerObj * const player = dynamic_cast<PlayerObj*>(myObjs[0])) {
        std::cout << player << "\n";
        player->lives = 2;
    }
    if (PlayerObj * const player = dynamic_cast<PlayerObj*>(myObjs[1])) {
        std::cout << player << "\n";
        player->lives = 2;
    }
    if (PlayerObj * const player = dynamic_cast<PlayerObj*>(myObjs[2])) {
        std::cout << player << "\n";
        player->lives = 2;
    }

    return 0;
}
1 голос
/ 05 февраля 2011

Ух, спасибо всем большое за ваши быстрые ответы!Просто отскочив, чтобы вы все знали, что вы помогли мне решить проблему, и теперь все работает отлично.

Я пошел с

if(myObjs[2].type == PlayerObj)
{
      (static_cast <PlayerObj*>(myObjs[2]))->lives = 0;
}

и добавил перечисление типа объекта в базовый класс.определить тип.

1 голос
/ 05 февраля 2011

Вы можете сделать так:

PlayerObj* player = dynamic_cast<PlayerObj*>(myObjs[2]);
if(player)
{
    player->lives = ...
}

или если вы уверены, что myObjs [2] имеет тип PlayerObj *, вы можете использовать:

(static_cast<PlayerObj*>(myObjs[2]))->lives = ...
...