我有一个基类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;
}


因此,当我返回诸如Rectangle之类的东西时,它们被强制转换为Shape。这完全不是我想要的。

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

最佳答案

创建对象后,就无法对其类型进行变形(例如,基于有关在运行时获取的按钮的信息)。将Rectangle返回为Shape具有切分对象的效果,因此调用方仅收到ShapeRectangle部分的副本,而不接收其余部分。

假设Shape是一个多态基类(即它提供了可能由派生类专用的虚函数),则Shape *(形状的指针)可以指向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;
}


起作用的原因是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);


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

因为active参数(按值)传递给函数并返回,所以分配返回值是必要的。如果不是

activeShape = updateShape(button, activeShape, leftClick);


你只是

updateShape(button, activeShape, leftClick);   // returned object is discarded


(即,不要将返回值赋给任何值),最终的结果是activeShape持有的对象将被销毁,并且任何使用它的尝试都会产生不确定的行为。

09-27 08:30