I have a vector of Base and Derived Class Objects, but I can't access data members inherited by derived objects that are stored in the vector - c++

Bear with me, I'm relatively new at C++.
Here is my project. I want to essentially create a simple game of chess.
I've got a base class gamePiece, which I'm thinking will eventually become an abstract class ( but right now it isn't)
The base class gamePiece has a bunch of data members in it: colorOfPiece, rankOfPiece, fileOfPiece, etc. It also has a function, void displayPieceInfo() which simply displays all of these values on the console via cout.
I am planning on having a number of derived classes from this one. Right now I have a "rook" subclass.
I want to add various types of pieces in a single vector, so I can later traverse it with an iterator.
Here is the problem I am running into.
vector<gamePiece> vectorOfAllGamePieces;
vector<gamePiece>::iterator itGamePieces;
I push_back a Rook into the vector as the first element. All the constructors look like they are running fine, initializing the variables. Yet when I try to run the display function on the first element, the strings are empty/unitialized.
itGamePieces=vectorOfAllGamePieces.begin();
itGamePieces->displayPieceInfo();
If I were to push in a generic gamePiece into the vector instead, everything would display properly.
Am I allowed to even have a vector like this with mixed types of objects -- for example, an object of a derived class, an object of the parent class, an object of a second class derived from the same parent
And if so, why do you suppose the values of the data members aren't showing up properly, even after I have set them in the constructor?

Not really, because of slicing. When you add a derived object to a vector<gamePiece>, it gets sliced and a gamePiece object is actually added to the vector.
You'll need to use a vector of (smart) pointers.

The problem is like this, Rook is a GamePiece. But You Cannot Store a Rook in a place for GamePieces. You can only cast a Pointer to Rook to a Pointer to GamePiece. So your vector must be saving NOT GamePieces but GamePiece * (Pointers to GamePieces).
std::vector<GamePiece *> vectorOfAllGamePieces;
But this could give you trouble in memory management. Another way is to store Handles without using pointers. ( a handle is something like a pointer to a pointer ). Or of course you can use smart pointers.
A quick hack will be ( this is a "hack" which is "evil" in the eyes of some people ),
std::vector<Rook> allRooks;
std::vector<Pawns> allPawns;
.....
std::vector<Queen> allQueens;
King theKing;
std::vector<GamePiece *> allPieces;
The allPieces will contain pointers to objects in the other vectors.
I think this is kind of OK when you know exactly all the types of pieces ( i guess this is chess ).

Related

Multiple object type container or dynamic casting for a game project?

I have a very specific... well, lets not call it a problem, lets rather call it a deadlock. I'm writing a simple 2d game using allegro5 along with c++, and have a specific problem I'd like to overcome.
Main problem:
Currently, for game loop i'm using a list container, which holds all of my objects (of type GameObject) inside, and then im iterating on it to do things like updating the objects positions, rendering and animatating sprites.
From the class GameObject (which hold generic information used for updating, rendering and memory handling methods) inherits a Creature class, which should handle things like attacking methods.
The problem that comes up is that when iterating my main list of GameObjects (which would include Creatures as well) i cannot directly use the methods of my Creatures class. Of course I understand why I cannot do that (Encapsulation).
So far I've come to few possible solutions (which, in my humble opinion are not perfect), but I would like to ask for help in helping to find easy to implement and efficient solution:
- Using a container that could hold multiple object types.
- Using dynamic_cast at some point, to cast a creature GameObjects to Creature class to temporary use Creature methods and variables (is that even possibile?)
- Setting up a second container for handling the Creature methods and variables (I would like avoid that, as then I would need a single object to be in two containers at once - when adding new types of classes 'buildings', 'obstacles' or 'arrows' thier number will grow!)
I'm a very beginner programmer, and as I understand creating a game could be kind of overkill for my level of skill, im determined to push this game forward with any means nessesary. (Especially since I've learned a lot so far)
I hope I've explained a problem in detail - i'm not posing any code here, as its more of a theoretical problem then practical one, im just iterating a GameObject list after all.
With regards,
As you've found out, containers can only hold one type of object at a time.
If that object type is a base class pointer, it can point to any object derived from the base class. However, you need to first cast the pointer to the appropriate type before you can use it's specific abilities.
You answered your own question when you brought up dynamic_cast.
You can use dynamic_cast on the base pointer stored in your container to determine if the object is actually of a different type derived from your base class.
See the section on dynamic_cast here :
http://www.cplusplus.com/doc/tutorial/typecasting/
Example
Derived* d = dynamic_cast<Derived*>(ptr_base_class);
if (d) {/* We now know that ptr_base_class holds an object of type Derived */}
else {
/// This object is not a Derived class type
}
However, if you had to iterate over your entire base class pointer list using dynamic_cast to determine if an object is of a specified type, it would be wasteful.
Here's where you answered your own question again. Keep a separate list of all Creature*s so you don't have to cast them. Yes, you will be using a /little/ more memory, but not much. Being able to iterate over the Creature list without iterating the entity list improves your performance. To make things easier, make your own container that has a list of each type of object as well as a main list of all objects. If you don't care about their derived class, iterate the main list. If you care about what class they are, iterate their specific list.

Store objects with different types that inherit the same class in a container

I have the following classes:
class ActivityItem : public QGraphicsItem;
class DeadTimeItem : public QGraphicsItem;
I am at a point where I need to store both objects of type ActivityItem and DeadTimeItem in the same container so I can work with them together.
What have I tried?
I tried creating a QVector that stores QGraphicsItem type, but I got the result that it cannot store abstract class types. What should I do?
My plan
My plan is to store these elements into QVector<T> member of a class timeline, because they will create a timeline. For example:
class timeline : public QGraphicsScene // is this a good idea? to inherit QGraphicsScene?
{
private:
QVector<QGraphicsItem*> items;
int left_offset; // this is for putting the items next to each other
public:
timeline();
void add_item( QGraphicsItem *item );
~timeline();
}
My timeline should look like the sketch below:
So, when the user calls add_item() method,
Timeline *timeline;
timeline->add_item( new ActivityItem( /* parameters */ ) ); // timeline->left_offset += 150;
timeline->add_item( new DeadTimeItem( /* parameters */ ) ); // timeline->left_offset += 100;
the left_offset increases depending on the type of the inserted item.
I know my post is quite long, but please read it completely, because I really need your help! Thank you!
As you've already guessed, I am using Qt. I can also use boost if it is really necessary.
Assuming
QGraphicsItem objects are part of the same scene and have a parent
The list is tightly tied to the scene (member variable of the same class which owns the scene, or member variable of a scene subclass).
Then you should use this:
QList<QGraphicsItem*> items; // or QVector or std::list, nearly same
These are raw pointers, they will not automatically delete the object when removed from list, nor will they get notified when item is deleted. Still, I don't know of a smart pointer type, which would work with QGraphicsItem, so raw pointers are what you must use. So if you need to also remove items dynamically, read on:
First of all, when you delete item, you need to also remove the pointer from this list, to avoid having dangling pointer. As an example, you may want to use something like QList::indexOf() and QList::removeAt() methods for this (also, if removal is very common and there are many items in the list, you may need to rethink the approach, as removing from an big array is slow). You need to be careful that item doesn't get deleted by some Qt code without you having a chance to remove it from the list.
Things get more complicated, if you may have items in the list, which also have their children in the list. If you just delete an item, it will delete it's children, so if your list has pointers to these and your list will end up with dangling pointers to those children. So, you need to do deletion very carefully. There are at least 3 different ways to go about this I can think of (recursive deletion in your own code, removing from list in item destructors, using event filter to catch item removals), so I can expand the answer, if this situation can happen in your code.
Final note: when the entire scene is deleted, it will delete all its children. Only thing you need to do here is make sure the pointers to deleted items in the list don't ever get used, for example simply by clearing the list.
You cannot create an instance of an abstract class, which is fortunate, because trying to assign a derived class to a base class provokes slicing or misbehaves in other interesting ways.
Due to the above restriction, no standard container for base can store a derived. You can circumvent this limitation by using pointers to base, either raw (non-owning) pointers or some smart-pointer type.
The answer using the standard library would be something like:
std::vector<std::shared_pointer<QGraphicsItem>> v;
Using QT classes:
QVector<QSharedPointer<QGraphicsItem>> qv;

Storing polymorphic game objects efficiently in a C++ container

For a 2D game I'm working on I have made a vector of pointers to an object. This object is the parent class where all other game objects inherit from. So the actor is such an object, items are, enemies are, etc. The class containing this vector (an object manager) executes virtual functions of this class, such as run() and draw().
For me this was just a straightforward implementation where I did not really think about at the time. Now I've come to a point where I actually have to delete objects from the container. Some quick searches on the internet tell me that a vector implementation is right for this task (using swap and pop), but also that I should store the objects themselves on the vector for even more performance. So: not pointers but the actual instances. This way they are allocated on the stack I guess. Is this even possible when using inheritance? And is there an even faster way to store inherited game objects?
Is this even possible when using inheritance?
No, it's not possible to store polymorphic objects in a container without using a pointer or a reference.
The way I would do it is with a combination of std::vector and std::unique_ptr:
template<class T> using container = std::vector<std::unique_ptr<T>>;
container<base> vector;
The pushing is made via:
vector.emplace_back(std::unique_ptr<base>(new item()));
vector.emplace_back(std::unique_ptr<base>(new enemy()));
where base is the base class and item and enemy are derived classes.

Regarding: Child Class in a Array C++

Regarding: Child Class in a Array C++
Hi guys, sorry as i am stuck on some work.
Basically this is what happen
I have a parent class call vehicle and it got 2 child class call
Car and Motorcycle
Parent class have the following value:
string Name: value either Car or MotorCycle
wheels : 4 or 2 (depends is car or motorcycle)
Notes On Wheel:
wheel[0] : Fine condition
wheel[1] : need some repair
wheel[2] : Fine condition
wheel[3] : Fine condition
I wonder how do i record this all in VehicleTwoD Array
Car / Motorcycle is a child class of Vehicle, what do you guys suggest. I try to create an object of VehicleTwoD vehtwod[100];
then i do a for loop to prompt. but how do i record the object car / motorcycle into my VehicleTwoD array and how do i record the string array inside too. so every VehicelTwoD array element contains the information
Name ( Motorcycle or Car)
Wheel ( depend on name - 2 or 4)
String array - notes size depend on what is choosen
How do i record all in 1 array.
Thank you very much , i know this is polymorphic and i know this is OOP and i know i need study more. but i really stuck on this part on creating such array that can hold other array.
THANKS!
Simplifying solution by not addressing irrelevant dimensionality of the storage array.
Create an array of Vehicle pointers, and store those:
vector<unique_ptr<Vehicle>> vehicles_;
vehicles_.push_back(new Car(...));
vehicles_.push_back(new Motocycle(...));
Since we're using unique_ptr here instead of a raw pointer, there's no need to explicitly delete.
By making the class polymorphic you can declare functions on the base class and implement class-spefici functionality by providing definitions in the derived classes. This makes it possible to call methods through a pointer to the base class without having to cast to the derived type.
If you need to call methods that exist only on a derived class, then you will need to cast the pointer. This should be done using dynamic_cast, and requires that your class is polymorphic.
EDIT:
Your comments suggest that you don't know how to use a vector and would prefer to use a raw array. That's fine too. Here's a simplified example that uses a C-style array of raw pointers. Note that by using neither vector nor a smart pointer like unique_ptr you make your code more brittle and prone to errors, and you often have to use a Magic Number for the array size (which is gross).
Vehicle* vehicles_[100];
vehicles_[0] = new Car(...);
vehicles_[1] = new Motorcycle(...);

dynamic_cast reference to base class in stl container

Is it possible to store a bunch of objects by their base class in say an std::list without pointers. I would really like the objects to be held in the container, then retrieve a pointer to the object in the container and dynamic_cast it to correct derived class.
I have it working fine using pointers. Like (super simple version):
class IComponent
{
virtual ~Icomponent(){}
}
class PositionComponent: public IComponent
{
//...
float x, y;
}
std::list<IComponent*> CList;
//...
// fill the list
// put reference to object in pComponent
//...
PositionComponent* position = dynamic_cast<PositionComponent*>( pComponent)
position->x = 346452.235612;
But the memory management is a huge pain. My actual structure is a
map<enumValue, map<int, IComponent*> >
I get the feeling I can't use the objects themselves because when I add any derived component into the list the extra data will be cut off and leave me with the base class only. This didn't figure this until I tried static_cast instead and it crashed.
Can answer my original question and/or confirm my feelings on the matter. Thanks!
to minimize pain of manual memory management use smart pointers: std::unique_ptr if your compiler already supports it or boost::shared_ptr, but not std::auto_ptr that is not supposed to be used in containers
As you guessed, when you stored an object in a container by value, it gets sliced and the data is chopped off.
If you only need to store one data type (you only show one in your code), then you can make the container hold that type.
If not, you really are stuck using pointers. You can make the memory management much easier by using a smart pointer, or if appropriate, a boost ptr_container of some sort.
Further you might want to think if you need to spend one more iteration considering your design to provide an interface that doesn't require doing a dynamic_cast to get the original type back out again.
Is it possible to store a bunch of objects by their base class in say
an std::list without pointers.
This sentence seems to be contrdicted in C++ point of view IMO. Because STL container can only hold same type of object, if you put derived object into a base type container, it got sliced.
So the apparent normal solution is to use container to hold base type pointers like you did(u could use boost/std smart pointer for memory management)
If you really want to store different objects in one STL container, you may want to consider use boost::any.