如何多态地使用指针的数组或向量?

时间:2015-06-15 16:20:56

标签: c++ arrays polymorphism

我已经在很多不同的帖子中读到了这个问题,不应该对数组进行多态处理,而应该使用指针数组,而且背后的推理对我来说很清楚。

但是,我找不到它是如何完成的例子,我似乎无法让它工作。请考虑以下代码:

#include <vector>

class Base
{
    public:
        Base();
        virtual ~Base();
};

class Derived : Base
{
    public:
        Derived();
        ~Derived();
};

void foo( std::vector<Base*> )
{
    // do something
}

int main()
{
    std::vector<Derived*> bar;
    foo(bar);

    return 0;
}

编译它会显示错误消息

could not convert 'bar' from 'std::vector<Derived*>' to 'std::vector<Base*>

我是否遗漏了某些东西,或者设计是否存在根本缺陷?提前谢谢。

3 个答案:

答案 0 :(得分:6)

std::vector<Derived*>std::vector<Base*>是不同的类型,它们之间没有转换。但看起来你需要的是

std::vector<Base*> bar;
foo(bar);

即。让多态性在向量元素的层次上起作用。

但请注意,为了在通常意义上使用多态,Derived必须从Base继承公开

class Derived : public Base
                ^^^^^^

struct Derived : Base

答案 1 :(得分:2)

要完成juanchopanza的回答,您可以使用std::vector<Derived*>

void itemfoo(Base* item)
{
    // do something
}

template<typename Iter>
void foo(Iter begin, Iter end) {
    // do stuff per element
    while(begin != end)
        itemfoo(*begin++);
}

int main()
{
    std::vector<Derived*> bar;
    foo(bar.begin(), bar.end());

    return 0;
}

如果你需要对整个范围进行操作并按Base*进行操作,那么你可以这样做:

void foo(Base** begin, Base** end) {
     // do stuff on range [begin, end)
}

int main()
{
    std::vector<Derived*> bar;
    if(bar.empty())
        foo(nullptr, nullptr); // or however you handle the empty range
    else
        foo(&bar[0], &bar[0] + bar.size());

    return 0;
}

答案 2 :(得分:1)

  

我是否遗漏了某些东西,或者设计是否存在根本缺陷?

std::vector<Derived*>的对象无法自动转换为std::vector<Base*>。它们是两种完全不同的类型。

我可以考虑以下选项来解决这个问题:

  1. foo更改为接受std::vector<Derived*>

    void foo( std::vector<Derived*> )
    {
        // do something
    }
    
  2. foo更改为功能模板。

    template <typename T>
    void foo( std::vector<T*> )
    {
        // do something with the implicit understanding that
        // T is derived from Base.
    }
    
  3. 更改主叫代码以使用std::vector<Base*>