In my code, I have a set of objects:
class Sphere { ...
class Plane { ...
...
And I need to use a collection of them (they will all have di
Creating containers of polymorphic types is a classical solutions, which comes with its own problems. One of which the types have to become polymorphic just in order to add them to a container -- not a good reason. Another problem is early and tight coupling resulting in more difficult maintenance and lack of flexibility, just in order to add them to a container -- not a good reason. Fortunately, in C++ there are better alternatives.
A better solution would be storing functions and not objects themselves in containers. The common reason why you want to put different types in the same container is to perform the same actions on all of them, for example, Sphere::Draw()
or Plane::Draw()
. What you can do is create a container of draw functions instead and erase type. E.g.
vector<function<void()>> drawings;
Sphere s;
Plane p;
drawings.push_back(bind(s, &Sphere::Draw));
drawings.push_back(bind(p, &Plane::Draw));
for(auto I = drawings.begin(); I != drawings.end(); ++i) (*i)();
By doing that you avoided strong coupling and other problems of inheritance, and got a more flexible, more general solution.
The above solution works only with C++11 as it requires std::function()
The classes would need to have a common base class, e.g.:
class MyBase { };
class Sphere : public MyBase { };
class Plane : public MyBase { };
Then in order to store polymorphic objects in a vector, you must store a pointer to them (because they can be different sizes from the base class). I recommend using a std::shared_ptr<MyBase>
or std::unique_ptr<MyBase>
(or use Boost if C++0x isn't available).
std::vector<std::shared_ptr<MyBase> > v;
v.push_back<std::shared_ptr<MyBase>(new Sphere());
v.push_back<std::shared_ptr<MyBase>(new Plane());
If there is no common base, you'd have to use void*
, or find a different way to do this.
Sphere and Plane would need a common base type, or your vector would need to be composed of void*
's.
Common base type (better):
class Shape { ... };
class Sphere : public Shape { ... };
class Plane : public Shape { ... };
std::vector<Shape*> shapes;
or void*
's (not great):
std::vector<void*> shapes;
Class Shape{...code...}
Class Sphere : public Shape{...code...}
Class Plane : public Shape{...code...}
std::vector<Shape*> List;
List.push_back(new Sphere);
List.push_back(new Plane);
or
//Base class to derived class
Shape* Shape_Sphere = new Sphere();
Shape* Shape_Plane = new Plane();
std::vector<Shape*> List;
List.push_back(Shape_Sphere);
List.push_back(Shape_Plane);
and if you want to delete the pointers
std::vector<Shape*>::iterator it;
for(it = List.begin(); it != List.end(); ++it)
{
delete *it;
}
Since the vector stores instances of Shape and Sphere/Plane are derived of the base class Shape, C++ will allow this to work
Are the objects related in a meanginful way? If they're not, then you probably shouldn't.
If they are, you'll want to do some reading on inheritance.
The other posts have told you most of what you need to know. I would like to add that boost has pointer containers that might be handy as they cleanup there contents when they are destroyed. Boost manual