【问题标题】:BOOST and C++: can't seem to get polymorphism to workBOOST 和 C++:似乎无法让多态性发挥作用
【发布时间】:2013-06-27 18:03:29
【问题描述】:

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

【问题讨论】:

    标签: c++ boost ptr-vector


    【解决方案1】:

    问题在于您的shape 是一个类型为Shape 的对象,而不是对(动态)类型为Circle 的对象的引用。

    多态性仅适用于引用或指针。当将对象视为并从派生类的对象中复制构造或移动构造基类的对象时,您得到的是slicing(绝对不是您想要的)。

    试试这个:

    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);
        //     ^^^^^^                                  ^^^^^^
    
        // ...
    }
    

    这就是说,有必要指出 (as Chad does in the comments) 你不需要在这里执行动态向下转换,因为print() 是一个虚函数。做的时候:

    shape.print();
    

    如果Shape 引用的对象是Circle 的实例,则函数调用将被分派到Circle::print()

    【讨论】:

    • 另请注意,由于print() 是一个虚函数,因此在这种情况下dynamic_cast 是不必要的。
    • @Chad:哦,对了,我错过了那部分。我会编辑,谢谢:)
    • @Chad:当我使用 for(auto const& shape : shapes) 时,当我尝试调用 shape.print() 时,它表示对象具有与成员函数不兼容的类型限定符:(
    • @dubesinhower:您应该将print() 设为const 成员函数(所以void print() const { ... }),因为它不需要更改调用它的对象的状态
    • @dubesinhower:很高兴它有帮助:)
    【解决方案2】:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-30
      • 2015-09-20
      • 2011-11-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多