我正在使用ptr_vector来存储"形状"。我试图用派生的形状类来填充它,比如"圆",每次我试图向下转换它们时,我都会得到糟糕的转换。
class Shape
{
public:
virtual ~Shape() {};
virtual void print() { std::cout << "shape" << std::endl; };
};
class Circle :
public Shape
{
public:
void print() { std::cout << "circle" << std::endl; };
};
int main()
{
boost::ptr_vector<Shape> shapes;
shapes.push_back(new Circle);
BOOST_FOREACH(Shape shape, shapes)
{
Circle& tempCircle = dynamic_cast<Circle&>(shape);
if(&tempCircle != NULL)
tempCircle.print();
}
system("PAUSE");
}
问题是shape
是一个类型为Shape
的对象,而不是对(动态)类型为Circle
的对象的引用。
多态性仅适用于引用或指针。当将对象视为值,并从派生类的对象复制基类的构造对象或移动基类的构造物体时,您得到的是切片(绝对不是您想要的)。
试试这个:
BOOST_FOREACH(Shape& shape, shapes)
// ^
使用对const
的引用也是有意义的,可能是因为您不会在循环中修改引用的对象,所以:
BOOST_FOREACH(Shape const& shape, shapes)
// ^^^^^^
{
Circle const& tempCircle = dynamic_cast<Circle const&>(shape);
// ^^^^^^ ^^^^^^
// ...
}
还要注意,C++11具有基于范围的for
循环,这使得BOOST_FOREACH
有点过时。因此,如果C++11是一个选项,你可以写:
for (auto const& shape : shapes)
{
Circle const& tempCircle = dynamic_cast<Circle const&>(shape);
// ^^^^^^ ^^^^^^
// ...
}
也就是说,有必要指出(正如Chad在评论中所做的那样),您不需要在这里执行动态下变频,因为print()
是一个虚拟函数。执行时:
shape.print();
如果Shape
引用的对象是Circle
的实例,则函数调用将被分派到Circle::print()
。
此外,您没有正确使用dynamic_cast。如果您dynamic_cast引用,而对象实际上不属于要将其强制转换到的类,则强制转换将抛出std::bad_cast
。它不会返回null,因为不存在具有null地址的引用。因此,以下是正确的方法:
Circle* tempCircle = dynamic_cast<Circle*>(&shape);
if(tempCircle != NULL)
tempCircle->print();
(实际上,您可以使用&r == NULL
来引用r
,但只有在取消引用具有未定义行为的空指针之后。)