在 c++ 中向下抛弃疑惑

Downcasting wondering in c++

本文关键字:抛弃 疑惑 c++      更新时间:2023-10-16

我有下一个代码

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;
}

代码未编译,因为形状不是圆(向下转换错误(。

我有点困惑。create(( 不是动态绑定?行

Circle* cp  = sp->create();  

不应该返回循环*?

这是因为那条线

Circle* cp = sp->create();

由编译器在编译时计算。在编译时,它只知道sp是指向Shape的指针,因此在编译时使用Shape::create()的签名。它无法知道指针指向什么,因为它是在运行时分配和设置的。要绕过它,请使用dynamic_cast.

Circle* cp = dynamic_cast<Circle*>(sp->create());

向下投射不是隐式的。既然你知道自己在做什么(即sp实际上是一个circle(,使用dynamic_Cast

Circle* cp  = dynamic_cast<Circle*>(sp->create());

您可以在静态类型为Shape的实例上调用create()。因此,函数签名是Shape* create()。事实上,在 vtable 查找之后,调用的实际函数是Circle::create()的,但是将Circle实例存储为Shape引用的目的是隐藏具体类型、其成员函数以及可能的协变返回类型。

要通过Circle::create()获取Circle对象,您可以

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();