开发者

problems accessing derived class in array

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 =开发者_JAVA百科 2;  // error is here
    return 0;
}

my problem is that i want to have an array of all my game objects so i can have them all together, but when i try to access myObjs[2]->lives I am unable to do so. This is the error I get:

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


myObjs is a pointer to base so it can access only base members


C++ is a statically typed language and this means that every variable has a specific type. Your array contains pointers to BaseObj and this means that the compiler will only allow access to the members defined in that class.

You can tell the compiler that indeed one of those pointers is pointing to a more specific (i.e. derived) class instance in two ways:

  1. dynamic_cast<PlayerObj*>(p)

    This expression will return a pointer to PlayerObj if indeed p was pointing to an instance of that class (or to an instance of a class derived from PlayerObj). If this is not the case however the returned pointer will be the null pointer even if p was not null.

    To be able to use dynamic_cast for a base->derived conversion you must be sure that Run-Time Type Information (RTTI) has been enabled if it's not elabled by default for your compiler and that your base class is a "polymorphic type", i.e. it must have at least one virtual method.

  2. static_cast<PlayerObj*>(p)

    This does the same conversion, however if p is not pointing to an instance of PlayerObj or of a class derived from PlayerObj then you are entering the "undefined behavior" land, exactly like when you write out of an array or use an object after you've deleted it. It may mean program crash, crazy behavior, daemons flying off your nose or even worse (e.g. that everything seems to work anyway and the crash will happen one million executed instuctions later).

Often a solution used in many C++ programs is to only use static_cast but eventually checking first the type of the pointed to instance by having a "type" data member (e.g. an enum) in the base class. This means that you're basically building your own RTTI instead of using the one provided by the compiler.


dynamic_cast is your friend:

#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;
}


You can do like this:

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

or if you are sure that myObjs[2] is of type PlayerObj* you can use:

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


Wow, thank you all so much for your quick replies! Just jumping back on to let you all know you helped me fix the problem and now it's all working perfectly.

I went with

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

and added an object type enum to the base class to define the type.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜