Reputation: 23
I'm programming a basic graphic scene editor with OpenGL and C++, and this is the context:
I have a Drawable class, which is abstract and has only one pure virtual function draw(). I'm using this class like a java interface.
Many classes that inherit from Drawable and reimplement draw().
A Scene class which contains a list of pointers to Drawables.
The main.cpp where I create that differents Drawable objects and add them to the list.
I'm having this issues:
Created objects in main.cpp constantly going out of scope, so it's not just easy as creating them and executing the adding function with a referenced object. (Just keeping a list with no valid pointers all the time).
A bittersweet solution is creating these new objects with new and letting the Scene class deleting the pointers in the list when it is destroyed, or deleting them in main.cpp somehow.
I don't really like this so I want to ask if there is some method to copy the objects inside the add function and then store the copy in the list, which it's not a problem because the copied object it's going to erase soon. Inside that function I don't know which subclass of Drawable I'm attending. I can't make a copy directly of the Drawable object because Drawable is an abstract class, can't make Drawable objects with new for the same. Just want to have a list with different objects which all can execute draw(). I leaving some code just in case:
class Drawable {
public:
virtual void draw() = 0;
virtual ~Drawable() = 0 {}
};
class Figure : public Drawable {
private:
list<Point, allocator<Point>> _points;
int _type;
public:
...
void draw() {
...
}
};
class Scene : public Drawable {
private:
list<Drawable*, allocator<Drawable*>> _drawables;
...
public:
...
void add(Drawable* drawable) {
_drawables.push_back(drawable);
}
~Scene() {
for(iterDrawable it = _drawables.begin(); it != _drawables.end(); ++it)
delete (*it);
}
void draw() {
for(iterDrawable it = _drawables.begin(); it != _drawables.end(); ++it)
(*it)->draw();
}
};
main.cpp
...
void display() {
...
Figure* square = new Figure(GL_POLYGON);
square->add(Point(xSquare, ySquare));
square->add(Point(xSquare + squareWidth, ySquare));
square->add(Point(xSquare + squareWidth, ySquare + squareHeight));
square->add(Point(xSquare, ySquare + squareHeight));
cScene.add(square);
cScene.draw();
...
}
...
I hope I explained sufficiently.
Upvotes: 2
Views: 785
Reputation: 119877
Drawable
must have a virtual destructor.delete
the list of its components before it itself goes away (that is, in the destructor). If the scene object is not the owner, and merely a user, then who is the owner? Can you guarantee that the owner will outlive all users? If not, how the owner will pass ownership to the next owner? If you are going to copy an object, you must decide this question for the original and for the copy.shared_ptr
and ptr_list
are fine and dandy, but I suggest learning the basics first. It is important to understand why shared_ptr
and ptr_list
are needed, which problems they purport to solve, and what their solutions look like from 30000 feet. The best way to acquire such understanding is by stumbling upon, and trying to solve, some of these problems.Drawable
must have a virtual destructor.draw()
for each derived class. The commonly accepted name for such a function is clone
. For each class Foo
, clone
would look like this:virtual Foo* clone() {
return new Foo(*this);
}
clone
look almost identically for all classes, nevertheless you do have to write each one of them manually. Note that this is using Foo
's copy constructor, which you will have to write yourself if Foo
owns any other object, or has a copy operation that is non-trivial in some other way.Drawable
must have a virtual destructor?Upvotes: 1
Reputation: 264461
What you want to use is a boost ptr container:
boost::ptr_list<Drawable> drawlables;
/// STUFF
drawlables.add(new Square);
The advantage of boost ptr containers (over a container of smart pointers) is that the container makes access to the elements look like objects (not pointers). This makes using them with the standard algorithms trivial.
The ptr containers take ownership of any pointer inserted into the container so memory mangement is covered. All other locations should be passed a reference from the container.
drawlables[0].draw();
// or drawl all of them
for_each(drawlables.begin(), drawlables.end(), std::mem_fun(&drawlables::draw));
Upvotes: 3