How to store different classes in the same vector?
So, I have a vector full of all objects for my game; things like player object, enemy object, walls, etc. All things in a vector are children Framework
, so I created a vector type Framework
because that was the closest thing to a generic data type for them.
The problem was that it was not executing overridden functions from the objects it was storing. So I parsed it to find out that I appear to be breaking up objects by storing them as Framework
. So now my question is, how do I keep all these objects in one list?
Just for reference, this is where functions are called that need to be overridden.
for (vector<Framework>::iterator num = gameObjects.begin(); num != gameObjects.end(); ++num)
{
//The current thing
Framework currentObject = *num;
currentObject.frameEvent();
currentObject.frameEndEvent();
currentObject.drawEvent();
}
Thanks in advance.
You need to keep pointers ( Framework*
) or std::shared_ptr< Framework >
(possibly std::unique_ptr< Framework >
) instances. This allows virtual calls and late binding - this means when you reference your objects, the correct function to call will be determined at runtime. Don't forget to make your functionsvirtual
Then your code (in a similar way)
for (vector< Framework* >::iterator num = gameObjects.begin(); num != gameObjects.end(); ++num)
{
Framework* currentObject = *num;
currentObject->frameEvent();
currentObject->frameEndEvent();
currentObject->DrawEvent();
}
However I would recommend sth like this (C ++ 11 required)
vector< std::unique_ptr< Framework > > gameObjects;
...
for (auto & currentObject : gameObjects)
{
currentObject->frameEvent();
currentObject->frameEndEvent();
currentObject->DrawEvent();
}
The latter (the range for the loop) should work regardless of the type used (as an example, you can use a regular pointer or shared_ptr or unique_ptr).
If you are interested in using unique_ptr
, please note that std::vector
you have to use to store them std::move
, as there can only be one instance std::unique_ptr
(as the name suggests), Consult this answer in case of problems.
To avoid overlapping objects, you need to use std::vector<Framework*>
or std::vector<std::unique_ptr<Framework>>
(or a smart pointer of your choice).
Sample code:
std::vector<std::unique_ptr<Framework>> gameObjects;
gameObjects.push_back(std::make_unique<Player>(/**/));
gameObjects.push_back(std::make_unique<Wall>(/**/));
And then
for (auto& currentObject : gameObjects)
{
currentObject->frameEvent();
currentObject->frameEndEvent();
currentObject->drawEvent();
}
Save pointers to Framework
and use polymorphism.
// Base class
class Framework {
// Make pure virtual if nothing is done here.
virtual void frameEvent(); // = 0;
// To ensure the derived instances are deleted properly.
virtual ~Framework(); // = default;
};
// Some specialized class
class SomeObject : public Framework {
void frameEvent() override; // C++11 style override.
};
std::vector<std::unique_ptr<Framework>> objects;
// Add a new SomeObject to the list
objects.emplace_back(new SomeObject());
Well, the straight answer is you don't. Or you will end up clipping objects that you have already encountered. You need to use the polymorphic capabilities of C ++ and store the common interface of your objects in a vector. Later, you can invoke the desired behavior by calling interface functions that have different implementations according to the actual type of the object.
You have to make frameEvent
, frameEndEvent
and drawEvent
virtual in Framework
. Then save std::shared_ptr
in your vector:
std::vector<std::shared_ptr<Framework>> objects;
objects.push_back(new GameObject());
for (vector<Framework>::iterator num = gameObjects.begin(); num != gameObjects.end(); ++num)
{
//The current thing
const Framework& currentObject = **num; // reference, don't copy anything if you don't need to
currentObject.frameEvent();
currentObject.frameEndEvent();
currentObject.drawEvent();
}
Note that you can save unique_ptr
to a vector if you are not using operations that require copying elements .
Another option, if you cannot make virtual functions and know what type of objects you are dealing with, you can do the first and then call non-virtual functions:
const PlayerObject& player = static_cast<const PlayerObject&>(*objects[0]);
player.frameEvent();
player.frameEndEvent();
player.drawEvent();
You need to keep pointers to your objects. If you have C++11
, then ideally you store them with std :: unique_ptr (assuming you have one main vector).
C ++ 03
std::vector<Framework*> gameObjects;
for(std::vector<Framework*>::iterator num = gameObjects.begin();
num != gameObjects.end(); ++num)
{
(*num)->frameEvent();
(*num)->frameEndEvent();
(*num)->drawEvent();
}
C ++ 11
std::vector<std::unique_ptr<Framework>> gameObjects;
for(auto& num: gameObjects)
{
num->frameEvent();
num->frameEndEvent();
num->drawEvent();
}
Store pointers in your vector instead of actual instances.
Another, possibly faster approach is to store them in separate vectors. This can be 50 times faster due to the higher caching efficiency.