我有一个基类 Shape
,它具有 Ellipse
和 Rectangle
等派生类。
在一个函数中,我有一个变量:
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
具有切片对象的效果,因此调用者仅收到 Shape
的拷贝Rectangle
的一部分,但不是其余部分。
假设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
持有的对象将被销毁,任何使用它的尝试都会产生未定义的行为。
关于C++ 如何返回未知的派生类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39824833/