这个问题在这里已有答案:
我有下一个代码
class Shape
{
public:
virtual Shape* create() { return new Shape; }
virtual void print() { cout << "Shape" << endl; }
virtual ~Shape() {}
};
class Circle : public Shape
{
public:
virtual Circle* create() { return new Circle; }
virtual void print() { cout << "Circle" << endl; }
};
void foo ()
{
Shape* sp = new Circle;
Circle* cp = sp->create();
cp->print();
delete sp;
delete cp;
}
代码未编译,因为Shape不是Circle(向下转换错误)。
我有点困惑。 create()不是动态绑定吗?这条线
Circle* cp = sp->create();
不应该回圆*?
向下倾斜不是隐含的。既然你知道你在做什么(即sp
实际上是circle
),请使用dynamic_Cast
Circle* cp = dynamic_cast<Circle*>(sp->create());
这是因为那条线
Circle* cp = sp->create();
由编译器在编译时进行评估。在编译时,它所知道的是sp
是指向Shape
的指针,因此Shape::create()
的签名在编译时使用。它无法知道指针指向的是什么,因为它是在运行时分配和设置的。要绕过它,请使用dynamic_cast
。
Circle* cp = dynamic_cast<Circle*>(sp->create());
您在具有静态类型create()
的实例上调用Shape
。因此,函数签名是Shape* create()
。实际上,在vtable查找之后,调用的实际函数是Circle::create()
,但是将Circle
实例存储为Shape
引用的点是隐藏具体类型,其成员函数以及可能的协变返回类型。
要通过Circle
获得Circle::create()
对象,您也可以
Circle *c1 = new Circle; // Static type info (Circle) is preserved
Circle *c2 = c1->create(); // Ok, the covariant return type is Circle*
要么
Shape *s1 = new Circle; // Everything Circle-related lost on the lhs
Circle *c1 = dynamic_cast<Circle*>(s1->create()); // Manually restore with RTTI
虽然后者更像是一个错误的提示(为什么你需要从基类接口创建子类实例而不隐藏它们的具体类型?)。
作为旁注,您还可以考虑更改函数签名,使其返回std::unique_ptr<Shape>
或std::unique_ptr<Circle>
,这对于返回多态类实例的工厂函数来说是一种很好的做法。
将形状指针转换为圆形。
Circle* cp = (Circle* sp)->create();