You could add a clone
method to your interface to, well, clone instances of your type hierarchy. Each concrete implementation produces a new instance of that specific class, so all type information is preserved.
class Object {
public:
virtual Object clone() = 0;
};
class Rectangle : public Object {
public:
virtual Rectangle clone() { /* create and return an identical Rectangle */ }
};
class Ellipse : public Object {
public:
virtual Ellipse clone() { /* create and return an identical Ellipse */ }
};
class Plane : public Rectangle {
std::vector<Object*> plane_objects;
public:
virtual Plane clone() { /* create and return an identical Plane */ }
void AddObject(const Object& object) {
plane_objects.push_back(object.clone());
}
};
This implies that the plane is the owner of all its objects, so it should also destroy them in its destructor. If those objects are accessed only internally, they can be stored with plain pointers - although even then smart pointers make disposal simpler and safer. If they are published, however, it is better to use smart pointers to store them.