I’ve a hierarchy of polymorphic classes, say a Shape abstract base class together with its derived classes, e.g. Rectangle, Circle, etc. Following the Virtual Constructor Idiom, I was wondering why we need that the return types of the virtual constructor functions in the derived classes should return the same type as in its parent class when using smart pointers?
For example, see the code below, where the clone() and create() member functions need to return smart_pointers to the Shape class. However, when using simple pointers, the return types can be of the same type as the one of the derived classes.
Could anybody explain why we need to handle those functions in the referred way?
class Shape;
typedef std::unique_ptr<Shape> shape_ptr;
class Shape{
public:
//typedef std::unique_ptr<Shape> shape_ptr;
Shape(){};
virtual ~Shape(){};
virtual void draw() const = 0;
virtual float area() const = 0;
virtual shape_ptr clone() const = 0;
virtual shape_ptr create() const = 0;
//virtual Shape*clone() const = 0;
//virtual Shape*create() const = 0;
};
class Rectangle:public Shape{
public:
typedef std::unique_ptr<Rectangle> rectangle_SmartPtr;
Rectangle(int height=0, int width=0):m_Height(height),m_Width(width){};
Rectangle(const Rectangle & rect):m_Height(rect.m_Height),m_Width(rect.m_Width){};
~Rectangle(){};
virtual void draw() const;
virtual float area() const;
//virtual rectangle_SmartPtr clone() const{ return rectangle_SmartPtr(new Rectangle(*this)); };
// error C2555: 'Rectangle::clone': overriding virtual function return type differs and is not covariant from 'Shape::clone'
//virtual rectangle_SmartPtr create() const{ return rectangle_SmartPtr(new Rectangle()); };
// error C2555: 'Rectangle::create': overriding virtual function return type differs and is not covariant from 'Shape::create'
virtual shape_ptr clone() const{ return shape_ptr(new Rectangle(*this)); }; //OK
virtual shape_ptr create() const{ return shape_ptr(new Rectangle()); }; //OK
//virtual Rectangle* clone() const{ return new Rectangle(*this); }; //OK
//virtual Rectangle* create() const{ return new Rectangle(); }; //OK
private:
int m_Height;
int m_Width;
};
class Circle:public Shape{
public:
typedef std::unique_ptr<Circle> circle_SmartPtr;
Circle(float radius=0):m_Radius(radius){};
Circle(const Circle & other):m_Radius(other.m_Radius){};
~Circle(){std::cout << "Circle destructor: " << this << std::endl; };
virtual void draw() const;
virtual float area() const;
//virtual circle_SmartPtr clone() const{ return circle_SmartPtr(new Circle(*this)); };
// error C2555: 'Circle::clone': overriding virtual function return type differs and is not covariant from 'Shape::clone'
//virtual circle_SmartPtr create() const{ return circle_SmartPtr(new Circle()); };
// error C2555: 'Circle::create': overriding virtual function return type differs and is not covariant from 'Shape::create'
virtual shape_ptr clone() const{ return shape_ptr(new Circle(*this)); }; //OK
virtual shape_ptr create() const{ return shape_ptr(new Circle()); }; //OK
//virtual Circle* clone() const{ return new Circle(*this); }; //OK
//virtual Circle* create() const{ return new Circle(); }; //OK
private:
float m_Radius;
};
When using raw pointers, the compiler allows for covariant return types but that’s not possible when using smart pointers since
unique_ptr< Rectangle >doesn’t derive fromunique_ptr< Shape >. The two classes are completely unrelated from the compiler’s perspective.