如何将 subclass 的向量传递给需要 base class 向量的函数

How can I pass a vector of subclass to a function that requires a vector of base class

我有一个 Base class 和一个 Sub class:

class Base{
  public:
    Base(){}
    // ...
};

class Sub: public Base{
    int param;
  public:
    Sub(){}
    // ...
};

我还有一个函数需要 Basevector,如下所示:

void doSomeThing(vector<Base> vectorOfBases){
    // ...
}

我需要这样调用函数:

vector<Sub> myVectorOfSubs;
doSomeThing(myVectorOfSubs);

编译器告诉我:

there is no appropriate conversion from vector< Sub > to vector< Base >

那么如何将 Sub class 的向量传递给需要 Base class 向量的函数?

So how can I pass a vector of Sub class to a function that requires a vector of Base class?

你不能。

std::vector<Base>std::vector<Sub> 之间没有超类-子类关系。

这是绕过该限制的一种方法。更改函数以使用可以与包含 BaseSub 对象的任何容器一起使用的函数模板。

template <typename Container>
void doSomeThing(Container& container)
{
   // Do something for each item of the container assuming that
   // the container contains objects of type Base or any of its derived classes.
   for ( Base& baseRef : container )
   {
     // Use baseRef
   }
}

vector<Base>vector<Sub> 分别保存实际的 BaseSub 对象。它们是不同的矢量类型,它们的数据数组也不同,所以你不能只传递一个 vector<Sub> 而应该是 vector<Base>。如果尝试使用 Sub 个对象构建 vector<Base>slicing will occur.

要使代码正常工作,您可以:

  • 将函数改为采用 vector<Base*>,然后您可以构造一个 vector<Base*>,其元素指向您的 vector<Sub> 元素,例如:

    void doSomeThing(std::vector<Base*> &vectorOfBasePtrs) {
        for (Base *b : vectorOfBasePtrs) {
            // ...
        }
    }
    

    std::vector<Sub> myVectorOfSubs;
    ...
    
    std::vector<Base*> myVectorOfBasePtrs;
    
    myVectorOfBasePtrs.resize(myVectorOfSubs.size());
    std::transform(myVectorOfSubs.begin(), myVectorOfSubs.end(), myVectorOfBasePtrs.begin(),
        [](Sub &s){ return static_cast<Base*>(&s); }
    );
    
    /* or:
    myVectorOfBasePtrs.reserve(myVectorOfSubs.size());
    for (Sub &s : myVectorOfSubs) {
        myVectorOfBasePtrs.push_back(&s);
    }
    */
    
    doSomeThing(myVectorOfBasePtrs);
    
  • 更改函数以采用 vector<T>,其中 T 是模板参数(理想情况下通过 std::enable_if and std::is_base_of 使用 SFINAE 以确保 T 实际上是 Base 或从 Base 派生的类型):

    template<typename T>
    void doSomeThing(std::vector<T> &vectorOfObjs) {
        for (Base &b : vectorOfObjs) {
            // ...
        }
    }
    

    std::vector<Sub> myVectorOfSubs;
    ...
    
    doSomeThing(myVectorOfSubs);
    
  • 更改函数以采用模板化 T 作为实际容器而不是容器元素类型:

    template<typename Container>
    void doSomeThing(Container &containerOfObjs) {
        for (Base &b : containerOfObjs) {
            // ...
        }
    }
    
  • 更改函数以获取一对迭代器而不是容器本身,然后您可以从 vector<Sub>:

    传入迭代器
    template <typename Iterator>
    void doSomeThing(Iterator begin, Iterator end) {
        while (begin != end) {
            Base &b = *begin;
            // ...
            ++begin;
        }
    }
    

    std::vector<Sub> myVectorOfSubs;
    ...
    
    doSomeThing(myVectorOfSubs.begin(), myVectorOfSubs.end());