Tin*_*Tin 6 c++ polymorphism virtual constructor smart-pointers
我有一个多态类的层次结构,比如一个Shape
抽象基类及其派生类,例如Rectangle
,Circle
等等.遵循Virtual Constructor Idiom,我想知道为什么我们需要在派生类中返回虚拟构造函数的类型应该在使用智能指针时返回与其父类相同的类型?
例如,请参阅下面的代码,其中clone()
和create()
成员函数需要返回smart_pointers
到Shape
类.但是,在使用时simple pointers
,返回类型可以与派生类之一具有相同的类型.
有人可以解释为什么我们需要以引用的方式处理这些功能吗?
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;
};
Run Code Online (Sandbox Code Playgroud)
使用原始指针时,编译器允许使用协变返回类型,但是在使用智能指针时这是不可能的,因为unique_ptr< Rectangle >
它不是从中派生的unique_ptr< Shape >
.这两个类与编译器的角度完全无关.
这称为协方差.
在类层次结构中,当基类指定返回a T*
或a 的虚方法时,T&
允许派生类返回U*
或U&
分别提供U
派生自T
(注意:显然是const
和volatile
组合).
这是一个特殊的规则,由编译器检查,它起作用,因为如果U
从那里派生,T
则U*
可以强制转换为a T*
.不幸的是,规则是有限的,因为它不适用于任何转换,因此即使你通常可以构建unique_ptr<Shape>
一个unique_ptr<Rectangle>
......协方差也行不通.
这就是为什么在其Cloneable概念中,Boost要求返回一个裸指针类型.这是一种耻辱,但却是获得协方差的唯一途径.