In the following, how can I make it such that the program uses the draw method from MainMenuScreen instead of the one from GameScreen?
class GameScreen {
public:
virtual void GameScreen::draw() {
cout << "Drawing the wrong one..." << endl;
}
};
class MainMenuScreen : public GameScreen {
public:
void MainMenuScreen::draw() {
cout << "Drawing the right one..." << endl;
}
};
class ScreenManager {
public:
list<GameScreen> screens;
// assume a MainMenuScreen gets added to the list
void ScreenManager::draw()
{
for ( list<GameScreen>::iterator screen = screens.begin();
screen != screens.end(); screen++ )
{
screen->draw(); /* here it uses the draw method from GameScreen,
but I want it to use the draw method from
MainMenuScreen */
}
}
};
PS: I do not want to make GameScreen::draw purely virtual, so please suggest something else.
how can I make it such that the program uses the draw method from
MainMenuScreen instead of the one from GameScreen?
You can't, unless you call it on a pointer or reference whose actual type is MainMenuScreen.
list<GameScreen> screens;
declares a list of objects, not pointers or references. If you add MainMenuScreen objects to it, they will lose type information because of object slicing and polymorphism will not work. You need:
list<GameScreen*> screens;
or, better yet:
list<shared_ptr<GameScreen> > screens;
You don't want to make draw pure virtual, but you do want to make it (or keep it) virtual. To go with that, you want to make screens a list of pointers (or possibly smart pointers of some sort) to GameScreens rather than a list of GameScreen objects.
As it is right now, when you (attempt to) insert your MainMenuScreen object into the list, it's being "sliced" to actually become a GameScreen object -- therefore, when you walk your list, you're walking a list of objects whose actual types are all GameScreen; hoping to get MainMenuScreen behavior from any of them at that point is futile.
With a list of pointers, a MainMenuScreen will remain exactly that, so when you invoke your virtual function, you'll get the behavior of the actual type.
You've fallen victim to object slicing. The objects in your list are only copies of the objects you inserted into it, and as each copy was made it got demoted to the contained type.
The way around this is to insert pointers (preferably smart pointers such as shared_ptr) into the list.
Related
There are some objects that are Drawable and some that are Movable.
All movable objects are dawable.
I store all the drawable objects in a vector called drawables and movable objects in a vector called movables.
I also have vectors ships and bullets which contain objects of type Ship and Bullet respectively.
Ship and Bullet both are Movable
Here's the structure of the classes:
class Drawable {
public:
void draw();
};
class Movable : public Drawable {
public:
void move();
}
class Ship : public Movable {
public:
Ship();
}
class Bullet : public Movable {
public:
Bullet();
}
The vectors are declared as follows:
std::vector<Drawable*> drawables;
std::vector<Movable*> movables;
std::vector<Ship*> ships;
std::vector<Bullet*> bullets;
The thing is, that each time I create a Ship I have to add it in all the vectors i.e.
drawables.push_back(ship);
movables.push_back(ship);
ships.push_back(ship);
I have created separate drawables and movables vectors since I have a draw() function which calls the draw() method of all objects in the drawables vector. Similarly, I have a move() function which calls the move() method of all objects in the movables vector.
My question is, how do I change the structure to prevent adding the same thing in different vectors. I also need to remove objects from all the vectors once it's purpose is done.
For example, once the bullet hits someone or moves out of the screen, then I'll have to remove it from the vectors drawables, movables and bullets after searching it in all three vectors.
It seems like I'm not using the correct approach for storing these objects. Please suggest an alternative.
This seems more like a software engineering question than a coding question. Please migrate the question to other forum if necessary.
Assuming you are using a reasonably modern compiler, this is exactly why shared_ptr exists.
The problem is that you have no idea which vector owns the object, so you don't know which one to delete. shared_ptr takes are of this for you: it manages the lifetime of the object, and will delete it once the last reference to the object is destroyed.
To create a new Ship, you could do something like this:
auto ship = std::make_shared<Ship>();
drawables.push_back(ship);
movables.push_back(ship);
ships.push_back(ship);
At this point ship has 4 references (one for each vector, and the ship variable itself). It will automatically be deleted once it has been removed from all three vectors and the local variable goes out of scope.
If you are going to maintain a container of (pointers to) all objects of a certain type, you may want to take a RAII approach. Have the object's constructor add to the container, and the destructor remove from it. You'd also want to make sure nothing else modifies the container, so it should be a private (static) member of your class, with a public method to provide read-only access.
Even better, move this logic into its own class, so it can be re-used. This would also allow your existing containers to remain focused on what they currently do. They would just need a new data member of the helper class type.
To ease removals, I would consider using a list instead of a vector. Also, it might be worth using reference_wrapper instead of pointers. A pointer can have a null value. While you can document that the container will have no null pointers, a reference_wrapper conveys this with no additional documentation.
To get you started, here is the start of a helper class template you could use.
template <class T>
class All {
using ListType = std::list< std::reference_wrapper<T> >;
private:
static ListType the_list;
// A list's iterators are rarely invalidated. For a vector, you would
// not store an iterator but instead search when removing from the_list.
typename ListType::iterator list_it;
public:
// Read-only access to the list.
static const ListType & list() { return the_list; }
// Construction
ListAll() : list_it(the_list.end()) {} // If this constructor is needed
explicit ListAll(T & data) : list_it(the_list.insert(the_list.end(), data)) {}
// Destruction
~ListAll() { if ( list_it != the_list.end() ) the_list.erase(list_it); }
// Rule of 5
// You should also define or delete the copy constructor, move constructor,
// copy assignment, and move assignment.
// If you need the default constructor, then you probably want a method like:
//void set(T & data);
};
template <class T>
typename All<T>::ListType All<T>::the_list{};
Names are often tough to come by. I named this template based on getting something to iterate over, for example: All<Movable>::list().
I want to write a function which takes as an argument an object from the class "Armor", however, when I call the function, I use instead an object from the base class "Item". Of course this object I use, even though may only be considered an "Item", may also be an "Armor". Only when I am sure it is an "Armor", I want to call the function.
In my case, I store items in a vector (these items can be armors). I want to get this item from the vector and call the function with it (equip the item, which I know is an armor).
class Item{
};
class Armor : public Item{
};
void equipArmor(Armor armor){ //Armor class argument
//Equip the armor
}
int main(){
vector<Item> items;
Armor a;
items.push_back(a);
equipArmor(items[0]); //Call function with an "Item" as an argument (even though it is in fact also an "Armor")
}
The problem
You have a vector of Item. When you push_back an Armor it will be sliced into an Item. So in the vector you have no longer an Armor but just an ordinary Item.
This is why your code won't work. First you cannot call your equipArmor() function with an Item, since it expects an Armor and downcasting is never implicit. But even if you could, you would always pass an Item value and never an Armor value.
The solution
To solve your issue, you need to work with pointers (better smart pointers) or references.
The first thing you will need to be able to work with polymorphic types and doing runtime type determination, is to have at least one virtual function in your base class:
class Item{
public:
virtual ~Item() {}
};
Now let's make your vector a vector of shared pointers. The nice thing is that those will ensure that objects will be destroyed when they are no longer used in any shared pointer. So less hassle with memory management, and less hassle with the rule of 3 :
vector<shared_ptr<Item>> items;
shared_ptr<Item> a = make_shared<Armor>();
items.push_back(a);
shared_ptr<Item> i = make_shared<Item>();
items.push_back(i);
equipArmor(items[0]); // lets just try the two possible cases
equipArmor(items[1]);
Finally, in your function, you can then sense for the real type and act accordingly, in a safe manner using dynamic_pointer_cast:
void equipArmor(shared_ptr<Item> item){ //Armor class argument
shared_ptr<Armor> a = dynamic_pointer_cast<Armor>(item);
if (a) {
cout << "Armor"<<endl;
}
else cout << "Item"<<endl;
}
Online demo
Remarks
If your type is not polymorphic, you cannot you dynamic_pointer_cast. You still could cast with a static_pointer_cast, but this is risky, because it requires you to know for sure that the casted smart pointer has the right type.
If you prefer raw pointers, you the same principles would apply, but yo'ud use dynamic_cast or static_cast respectively. But again, static_cast requires you to be absolutely sure of the type. And how can you be, if you have a vector full of random items ?
You want to cast from the base class (Item) to the subclass (Armor). This is impossible.
You could do this if items would be a vector of pointers to Items. You can then cast an Item * to an Armor * if you are sure that the underlying object is actually an Armour.
int main(){
std::vector<Item *> items;
Armor a;
items.push_back(&a);
// This only works if items[0] points to an Armor object
equipArmor(*static_cast<Armor *>(items[0]));
}
I'm using shared_ptr<Base> for some sort of tree list with derived classes. But I'm getting a pointer acces violation when my tree gets destructed.
My code looks something like this, besides, this actually similates my runtime error:
#include <iostream>
#include <memory>
#include <vector>
class Base;
typedef std::shared_ptr<Base> pBase;
class Derived;
class Base {
public:
std::vector<pBase> children;
pBase parent;
Base() {}
virtual ~Base() {}
virtual void doSomething() {}
void add(pBase i);
};
class Derived : public Base {
void doSomething() {
// Do something...
}
};
void Base::add(pBase i) {
i->parent = pBase(this);
children.push_back(i);
}
int main() {
pBase tree = pBase(new Derived());
pBase child(new Derived());
child->add(pBase(new Derived()));
tree->add(child);
}
Also when I add the following lines to Base::~Base:
std::cout << "destruct " << name << std::endl;
And implement a std::string called name in Base which is different for each instance, I can see that the destructor is called multiple times (because of the Base::parent reference I think). That ofcourse triggered my error, but I still don't understand why it happens because shared_ptr<Base> is expected to count its references before actually destroying it!!?
I hope some can tell me what I'm doing wrong!
But more important, how I can fix this!
Look at this line in add()
i->parent = pBase(this);
Each time you call add, you're creating a new shared pointer to this. These shared pointer are separate - that is, they are NOT 'shared' as you think. So, the first time you delete a child, it's parent gets deleted (because it's a shared pointer). Hence your code blows up.
Try (as a start) making parent a plain dumb pointer.
Base *parent;
Just to add to the others' answers: The canonical way to do what you want in the line
i->parent = pBase(this);
is to use std::enable_shared_from_this. You
Derive Base from it
class Base : std::enable_shared_from_this<Base> {
Ensure that every Base instance is owned by a std::shared_ptr. That is OK in your case, since you create the objects in expressions like
pBase child(new Derived());
Use shared_from_this() instead of this when you want a std::shared_ptr. The problematic line will then become
i->parent = shared_from_this();
Here
i->parent = pBase(this);
you create a smart pointer from a plain old pointer to an object which you didn't get directly from new. Never do this.
As #Roddy explained, you get separate smart pointer objects, with separate reference counters. Two reference counters for one pointee won't work.
In your case, it's probably ok to make parent a normal pointer, as #Roddy proposed. This way, you don't get in trouble with cyclic references. Just be sure that you never access the parent pointer after you deleted the parent. No problem if you delete all the children together with the parent (which happens automatically, unless you store more smart pointers to them, somewhere else)
If you want to initialize a smart pointer, you've got two choices, basically: Use smart pointers in every interface. Unfortunately that doesn't work for "this" because that's an implicit parameter. You would need to pass the smart pointer, which you already created, to the method manually, in an extra parameter. Like this:
tree->add(tree, child);
Which is kind of ugly, so you may want to consider making "add" a static method, so you won't need to pass the parent twice.
The other choice: Use another kind of smart pointer, like boost::intrusive_ptr, where you can store the reference count in the pointee. This way, you are able to find the reference count, even if you've got only a dumb pointer like "this".
Edit: The answer by #jpalecek, below, is better. Use that one. Sebastian.
If I have several levels of object containment (one object defines and instantiates another object which define and instantiate another object..), is it possible to get access to upper, containing - object variables and functions, please?
Example:
class CObjectOne
{
public:
CObjectOne::CObjectOne() { Create(); };
void Create();
std::vector<ObjectTwo>vObejctsTwo;
int nVariableOne;
}
bool CObjectOne::Create()
{
CObjectTwo ObjectTwo(this);
vObjectsTwo.push_back(ObjectTwo);
}
class CObjectTwo
{
public:
CObjectTwo::CObjectTwo(CObjectOne* pObject)
{
pObjectOne = pObject;
Create();
};
void Create();
CObjectOne* GetObjectOne(){return pObjectOne;};
std::vector<CObjectTrhee>vObjectsTrhee;
CObjectOne* pObjectOne;
int nVariableTwo;
}
bool CObjectTwo::Create()
{
CObjectThree ObjectThree(this);
vObjectsThree.push_back(ObjectThree);
}
class CObjectThree
{
public:
CObjectThree::CObjectThree(CObjectTwo* pObject)
{
pObjectTwo = pObject;
Create();
};
void Create();
CObjectTwo* GetObjectTwo(){return pObjectTwo;};
std::vector<CObjectsFour>vObjectsFour;
CObjectTwo* pObjectTwo;
int nVariableThree;
}
bool CObjectThree::Create()
{
CObjectFour ObjectFour(this);
vObjectsFour.push_back(ObjectFour);
}
main()
{
CObjectOne myObject1;
}
Say, that from within CObjectThree I need to access nVariableOne in CObjectOne. I would like to do it as follows:
int nValue = vObjectThree[index].GetObjectTwo()->GetObjectOne()->nVariable1;
However, after compiling and running my application, I get Memory Access Violation error.
What is wrong with the code above(it is example, and might contain spelling mistakes)?
Do I have to create the objects dynamically instead of statically?
Is there any other way how to achieve variables stored in containing objects from withing contained objects?
When you pass a pointer that points back to the container object, this pointer is sometimes called a back pointer. I see this technique being used all the time in GUI libraries where a widget might want access to its parent widget.
That being said, you should ask yourself if there's a better design that doesn't involve circular dependencies (circular in the sense that the container depends on the containee and the containee depends on the container).
You don't strictly have to create the objects dynamically for the back pointer technique to work. You can always take the address of a stack-allocated (or statically-allocated) object. As long as the life of that object persists while others are using pointers to it. But in practice, this technique is usually used with dynamically-created objects.
Note that you might also be able to use a back-reference instead of a back-pointer.
I think I know what's causing your segmentation faults. When your vectors reallocate their memory (as the result of growing to a larger size), the addresses of the old vector elements become invalid. But the children (and grand-children) of these objects still hold the old addresses in their back-pointers!
For the back-pointer thing to work, you'll have to allocate each object dynamically and store their pointers in the vectors. This will make memory management a lot more messy, so you might want to use smart pointers or boost::ptr_containers.
After seeing the comment you made in another answer, I now have a better idea of what you're trying to accomplish. You should research generic tree structures and the composite pattern. The composite pattern is usually what's used in the widget example I cited previously.
Maybe all your object can inherit from a common interface like :
class MyObject
{
public:
virtual int getData() = 0;
}
And after you can use a std::tree from the stl library to build your structure.
As Emile said, segmentation fault is caused by reallocation. Exactly speaking -- when the local stack objects' 'this' pointer was passed to create another object, which is then copied to the vector container. Then the 'Create()' function exits, the stack frame object ceases to exist and the pointer in the container gets invalid.
Please let me know which one is good
Consider I have a class like this
class Shape
{
public:
virtual void Display()
{
cout << "Shape::Display()" << endl;
}
};
class Line : public Shape
{
public:
void Display()
{
cout << "Line::Display()" << endl;
}
};
class Circle : public Shape
{
public:
void Display()
{
cout << "Circle::Display()" << endl;
}
};
1)
class Container
{
public:
Container(Shape& shape) : m_Shape(shape)
{
}
void Draw()
{
m_Shape.Display();
}
private:
Shape& m_Shape;
};
Here he is taking reference and assigning it to the base class object.
2)
class ShapeContainer
{
public:
ShapeContainer(Shape* pShape) : m_pShape(pShape)
{
}
void Draw()
{
m_pShape->Display();
}
private:
Shape* m_pShape;
};
Here he is taking the pointer and assigning it to the base class object.
Please let me know which one is good or when to use them
The decision has to be taken in terms of what you want to do with your object. Since you are not including the option of storing a value, I will assume that you need the container to refer to an external object. If this is not a requirement, consider using what standard containers do: store a copy of the object.
By using a reference you avoid having to check for NULL on creation (after creation both solutions share the same problem there: the external object might be destroyed, leaving you with a dangling reference and Undefined Behavior). The semantics of a reference are a little stronger, and anyone that reads the code will immediately understand: This container is meant to hold a reference to this object for the whole lifetime of the container, the object lifetime is managed externally.
On the negative side of it, references are not resettable, once you set a reference it becomes an alias to the object, and you cannot reset it to refer to a different object. This means that a container that holds a reference will not be assignable by default as you cannot make it refer to a different object. Even if you provide a custom assignment operator, the reference cannot be changed and it will keep referring to the old object. You will not be able to provide member functions in the container to refer to a different object: once you set a reference, it is set forever.
Pointers on the other hand, can be NULL, so you might want/need to check for validity of the pointer before use. They are resettable, and you can offer operations to have your container refer to a different object at any point, by default the container will be assignable. On the negative side, pointers can be used in different scenarios, so the semantics are not so clear. In particular, you will have to carefully document on the interface whether the container takes ownership of the pointer (and the responsibility to release the memory) or not. If you are going to handle ownership inside the container, then consider using a smart pointer (or else just make a copy and forget the original if you can, which will be less error prone).
I perosnally prefer using references over pointers whenever possible. This avoids having to do a NULL check before using the pointer as references can not be NULL. BTW, your shape class requires a virtual destructor.
I'd rather say that there is no good or bad in this case, it's just a matter of what you want to do.
If the user is not allowed to store NULL pointers in your vector because it's a requirement, then use by reference. But if the user wants to reserve space for 10 objects but only wishes to have the first 3 initialized, then you'd want to be able to store NULL to be able to differentiate between objects and empty space.
But as said, it's a matter of requirement for the container.
In your case i'd choose by reference.
I would go for the reference approach if there is no need to explicitly control the lifetime of the contained object in the container class and you can be sure that the passed reference object is always valid during the lifetime of the container class.