C++如何返回未知的派生类?

Jea*_*ean 0 c++ polymorphism inheritance

我有一个基类Shape,派生类和EllipseRectangle.

在一个函数中,我有一个变量:

Shape activeShape(black, black, {0,0}, {0,0}, false);

后来在那个函数中:

activeShape = updateShape(isButton, activeShape, true);

updateShape 看起来像这样:

Shape updateShape(int button, Shape active, bool leftClick)
{
    switch(button)
    {
        case 1:
            return active;
        case 2:
            return Line(active.getFillColor(), active.getBorderColor(), active.getP1(), active.getP2(),false);
            break;
        case 3:
            return Rectangle(active.getFillColor(), active.getBorderColor(), active.getP1(), active.getP2(),false);
            break;
        case 4:
            return FilledRectangle(active.getFillColor(), active.getBorderColor(), active.getP1(), active.getP2(),false);
            break;
        case 5:
            return Ellipse(active.getFillColor(), active.getBorderColor(), active.getP1(), active.getP2(),false);
            break;
        case 6:
            return FilledEllipse(active.getFillColor(), active.getBorderColor(), active.getP1(), active.getP2(),false);
            break;
        default:
            if(leftClick)
            {
                active.setColor(getEnumColor(button), active.getBorderColor());
            }
            else
                active.setColor(active.getFillColor(), getEnumColor(button));
            break;
    };
    return active;
}
Run Code Online (Sandbox Code Playgroud)

因此,当我回归之类的时候Rectangle,它们就像是一样Shape.这不是我想要的.

我需要做什么activeShape才能成为Shape派生类之一?

Pet*_*ter 5

一旦创建了对象,就不可能变形其类型(例如,基于在运行时获得的按钮的信息).返回a Rectangle作为Shape具有切片对象的效果,因此调用者只接收该Shape部分的副本Rectangle,而不是其余部分的副本.

假设Shape是一个多态基类(即它提供了可能由派生类专门化的虚函数),Shape *(指向形状的指针)可以指向a Rectangle.但是,必须正确管理对象的生命周期.

您可以使用智能指针处理所有这些,例如,在C++ 11及更高版本中std::unique_pointer<Shape>.

std::unique_pointer<Shape> updateShape(int button,
        std::unique_pointer<Shape> active, bool leftClick)
{
    switch(button)
    {
        case 1:
             break;    // don't change active
        case 2:
            active = new Line(active->getFillColor(), active->getBorderColor(), active->getP1(), active->getP2(),false);
            break;
        case 3:
            active = new Rectangle(active->getFillColor(), active->getBorderColor(), active->getP1(), active->getP2(),false);
            break;
        case 4:
            active = new FilledRectangle(active->getFillColor(), active->getBorderColor(), active->getP1(), active->getP2(),false);
            break;
        case 5:
            active = new Ellipse(active->getFillColor(), active->getBorderColor(), active->getP1(), active->getP2(),false);
            break;
        case 6:
            active = new FilledEllipse(active->getFillColor(), active->getBorderColor(), active->getP1(), active->getP2(),false);
            break;
        default:
            if(leftClick)
            {
                active->setColor(getEnumColor(button), active->getBorderColor());
            }
            else
            {
                active->setColor(active->getFillColor(), getEnumColor(button));
            }
            break;
     }
     return active;
}
Run Code Online (Sandbox Code Playgroud)

这样做的原因是std::unique_pointer管理动态分配(使用运算符创建new)对象的生命周期.它通过存储指向对象的指针,并指定std::unique_pointer<Shape>更改指针(使其指向不同的对象)来完成此操作.重要的是,分配给智能指针也会释放它先前管理的对象.

请注意,因为在生命周期结束时std::unique_pointer将使用运算符delete来销毁包含的对象,所以Shape必须有一个虚拟析构函数.如果不这样做,将导致使用运算符时出现未定义的行为delete.

使用这个就像是

 std::unique_pointer<Shape> activeShape(new Rectangle( whatever_parameters));

 activeShape = updateShape(button, activeShape, leftClick);
Run Code Online (Sandbox Code Playgroud)

请记住,这activeShape是一个智能指针.因此,使用包含的Shape对象需要指针语法(activeShape->whatever)而不是成员语法(activeShape.whatever).

因为active参数(通过值)传递给函数并返回,所以指定返回值是必需的.如果,而不是

activeShape = updateShape(button, activeShape, leftClick);
Run Code Online (Sandbox Code Playgroud)

你干脆

updateShape(button, activeShape, leftClick);   // returned object is discarded
Run Code Online (Sandbox Code Playgroud)

(即不将返回值赋值给任何东西),净效果是activeShape被销毁的对象将被销毁,任何使用它的尝试都会给出未定义的行为.

  • 如果你的`unique_pointer`是`unique_ptr`,那么这段代码将无法编译,因为你不能将`activeShape`复制到`updateShape`的参数中. (2认同)