2

我正在使用 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");
}
4

2 回答 2

6

问题是您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();

如果Circle::print()引用的对象ShapeCircle.

于 2013-06-27T18:04:33.133 回答
0

此外,您没有正确使用 dynamic_cast 。如果您 dynamic_cast 引用,并且该对象实际上不属于您将其转换为的类,则转换将 throws std::bad_cast。它不会返回 null,因为不存在带有 null 地址的引用之类的东西。所以这是正确的方法:

Circle* tempCircle = dynamic_cast<Circle*>(&shape);
if(tempCircle != NULL)
    tempCircle->print();

(您实际上可以使用 进行引用r&r == NULL但只能在取消引用具有未定义行为的空指针之后。)

于 2013-06-27T18:29:00.253 回答