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:
dynamic_cast<PlayerObj*>(p)
This expression will return a pointer to
PlayerObj
if indeedp
was pointing to an instance of that class (or to an instance of a class derived fromPlayerObj
). If this is not the case however the returned pointer will be the null pointer even ifp
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.static_cast<PlayerObj*>(p)
This does the same conversion, however if
p
is not pointing to an instance ofPlayerObj
or of a class derived fromPlayerObj
then you are entering the "undefined behavior" land, exactly like when you write out of an array or use an object after you'vedelete
d 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.
精彩评论