Reputation: 566
So I have a vector full of all the objects for my game; things like the player object, enemy object, walls, etc... All things in the vector are children of Framework
, so I made the vector type Framework
because that was the closest thing to a universal data type for them.
The problem was it wasn't running overridden functions from the objects it stored. So I Googled it to find out apparently I'm object slicing by storing them as Framework
. So my question is then, how do store all these objects in one list?
Just for reference, this is where the supposed-to-be-overridden functions are called.
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.
Upvotes: 3
Views: 1700
Reputation: 6240
Another, possible faster approach is to store them in separate vectors. It can be 50 times faster due to higher cache efficiency.
Upvotes: 0
Reputation: 48655
You need to store pointers to your objects. If you have C++11
then ideally you will store them using std::unique_ptr (assuming you have one master 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();
}
Upvotes: 1
Reputation: 1679
Store pointers to Framework
and make use of 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());
Upvotes: 2
Reputation: 8617
You have to make frameEvent
, frameEndEvent
and drawEvent
virtual in Framework
. Then, store 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 store a unique_ptr
in a vector as long as you don't use operations that require copying elements.
Another option, if you can't make the functions virtual and know what type of object you are dealing with, you can cast first and then call the non-virtual functions:
const PlayerObject& player = static_cast<const PlayerObject&>(*objects[0]);
player.frameEvent();
player.frameEndEvent();
player.drawEvent();
Upvotes: 1
Reputation: 2263
You have to store pointers (Framework*
), or std::shared_ptr< Framework >
(possibly std::unique_ptr< Framework >
) instances. That allows to use virtual calls and late binding - meaning that when you refer to your objects, the right function to call will be determined at runtime. Don't forget to make your functions virtual
Then, your code (in similar fashion)
for (vector< Framework* >::iterator num = gameObjects.begin(); num != gameObjects.end(); ++num)
{
Framework* currentObject = *num;
currentObject->frameEvent();
currentObject->frameEndEvent();
currentObject->DrawEvent();
}
However, I'd recommend sth like this (c++11 required)
vector< std::unique_ptr< Framework > > gameObjects;
...
for (auto & currentObject : gameObjects)
{
currentObject->frameEvent();
currentObject->frameEndEvent();
currentObject->DrawEvent();
}
Last one (range for loop) should work regardless of the type used (you may use normal pointer or shared_ptr or unique_ptr as example shows).
If you are interested in using unique_ptr
, please note that in order to store these on std::vector
, you have to use std::move
, as there can only be one instance of std::unique_ptr
(as name suggests). Consult this answer in case of problems.
Upvotes: 7
Reputation: 218268
You have to use std::vector<Framework*>
or std::vector<std::unique_ptr<Framework>>
(or smart pointer of your choice) to avoid object slicing.
Code example:
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();
}
Upvotes: 2
Reputation: 18368
Well, the straight answer is - you don't. Or you'll get object slicing that you already encountered. You need to use the polymorphic abilities of C++ and store the common interface of your objects in the vector. Later you can invoke the desired behavior by calling the interface functions that have different implementation according to the actual object type.
Upvotes: 1