Given a base class of gameObject
and a derived class of animatedGameObject
, I thought it may be good to store all of their instances in an std::vector
. If the vector GameObjects
is declared to be the base type of gameObject*
, derived object instances require casting.
Example:
vector<gameObject*> GameObjects;
gameObject A* = new gameObject( ...init... );
animatedGameObject B* = new animatedGameObject( ...init... );
GameObjects.push_back(A);
GameObjects.push_back(B);
// to access the animatedGameObject functions:
static_cast<animatedGameObject*>(GameObjects[1])->functionUniqueToAnimated();
Being afraid as per usual, I turned to Scott Meyers (Effective C++, 3rd Edition), who writes on the subject:
Many programmers believe that casts do nothing but tell compilers to treat one type as another, but this is mistaken. Type conversions of any kind (either explicit via casts or implicit by compilers) often lead to code that is executed at runtime.
I've read through his Item 27: Minimize Casting twice, yet given my inexperience with this, I am struggling with my inability to answer a simple question "IS THIS A DUMB THING TO DO?"
I should mention that there are several reasons why it is a dumb thing to do that have nothing to do with invoking static_cast
. The questions, in order of importance, are:
static_cast
in my example above?std::vector
for such approaches? (only if there's one that is obvious, I'm not asking you to do my research for me.)This is my first time asking a question here, so apologies in advance, where necessary.
static_cast
is not the right tool for the job, unless you know that the pointer goes to an animatedGameObject
and not a gameObject
. What data structure are you using to store that information?
Determining the type of a derived object after a base pointer is the job of dynamic dispatch or dynamic_cast
. In your example, the call GameObjects[1]->draw()
should work with no cast because draw
should be a virtual function. Otherwise you can use dynamic_cast< animatedGameObject & >( * GameObjects[1] )
to assert that the object is an animatedGameObject, and throw a std::bad_cast
exception if it's not. (This would still require a virtual
function in class gameObject
, usually its destructor.)
But doing static_cast
to a polymorphic derived type is a code smell.
Also you ask whether std::vector
is a good data structure for this use case. It is, but not a vector of "naked" pointers. C++11 now provides "smart pointer" memory management classes which perform new
and delete
for you, rendering the actual operators all but obsolete. Look into std::unique_ptr
for this case.
In general, casting base class to derived class is unsafe. In those situations it makes sense to use dynamic_cast. Dynamic_cast returns NULL, if conversion cannot be performed.
Are there better data structures than
Well, IF your gameObjects are not automatically deleted elsewhere, it might make sense to use something like std::vector<std::shared_ptr<gameObject> >
. However, standard shared pointers may introduce hidden overheads (extra new/delete, in worst case scenario they might even introduce multithreaded mutex lock, IF they're designed to be thread-safe), so you should make sure those overheads are compatible with your goals.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With