繁体   English   中英

传递派生类型的 std::vector,其中需要基类型的 std::vector

[英]Passing std::vector of derived type where a std::vector of base type is expected

我有一个基类:

class Member
{
    ....
}

和一个派生类,像这样:

class Mine_sweeper : private Member
{
    ....
}

然后我有一个容器:

class Population
{
public:
    std::vector<Member>& m_members;
    Population(std::vector<Member>& members);
}

当我将 Population 的构造函数与成员向量一起使用时,它编译正常。 但是,如果我尝试将 Population 的 m_members 与 Mine_sweepers 的向量联系起来,编译器就会抛出错误。

std::vector<Member> members;
Population pop(members); // this compiles OK

std::vector<Mine_sweeper> sweepers;
Population pop(sweepers); // but here I get an error
main.cpp(23): error C2664: 'Population::Population(std::vector &)' : cannot convert parameter 1 from 'std::vector' to 'std::vector &'

你不能。 不是这样。 这是因为std::vector<B>不是从std::vector<A>派生的,不管B是从A派生的事实。

但是等等......让我们用一个最小的例子来简化你的问题:

struct A {};
struct B : A {};
void f(std::vector<A> const&) {}

int main()
{
    std::vector<A> vecA;
    std::vector<B> vecB;
    f(vecA);
    f(vecB); // error
}

在这里,与您的示例代码不同, B公开继承自A 您仍然无法将std::vector<B> const&给需要std::vector<A> const&因为不存在从std::vector<B>std::vector<A>隐式转换.

在以下情况下,可以发送B const& ,其中需要A const& ,因为 C++ 提供了从对派生类型的引用到对基类型的引用的隐式转换。

struct A {};
struct B : A {};
void f(A const&) {}

int main()
{
    A alice;
    B bob;
    f(alice);
    f(bob);
}

一种解决方案是使用现有的从BA隐式转换提供显式转换:

struct A {};
struct B : A {};
class Container
{
    std::vector<A*> _items;
public:
    template<class T>
    Container(std::vector<T> v)
        : _items(v.begin(), v.end())
    {}
    // other stuff, see rule of 5
};


int main()
{
    std::vector<A*> vecA;
    std::vector<B*> vecB;

    Container contA(vecA);
    Container contB(vecB);
}

一旦你有一个基本的工作转换,你需要弄清楚如何使用std::unique_ptrstd::shared_ptrstd::weak_ptr处理内存所有权。

Mine_sweepers 的向量不是成员的“类”向量,即使 Mine_sweeper 是“类”成员也是如此。 您不能使用vector<Derived>代替vector<Base>

使用vector<unique_ptr<Member>>而不是vector<Member> AND vector<Mine_sweeper> 这使您能够拥有不同的成员人口(即,Mine_sweepers 和其他成员子类型,同时)。

或者,将 Population 类转换为类模板:

class Population<T>
{
public:
    std::vector<T>& m_members;
    Population(std::vector<T>& members);
}

这样,一个 Population 实例可能只包含一种类型的成员。

Population 类的构造函数将参数传递给一个包含 Member 类数组的向量。 您可以将派生类传递给将基类作为参数的对象,或者从派生到基类向上转换,但是您在这里所做的不同。 您不是将派生类发送到采用基类参数的函数,而是完全发送不同的不相关类型,而是将 std::vector< typeA> 发送到需要 std::vector< typeB> 的对象.

当您在编译时创建 std::vector< int> 时,它将创建包含所有特定细节的向量类,例如它如何迭代整数等。这是一个数组或“整数”。 将它传递给采用双精度数组的函数是否有意义? 然后该函数正在处理双精度数,例如移动到下一个双精度数它可能向前移动 8 个字节而不是 4 个字节,它会做错事。

您必须手动制作两个版本的 Population 类或使用模板来完成。 编辑:见 YSC 的回答,他模板构造函数

或者,您可能想要一个向量/数组,它可以包含两种类型的类,Base 和 Minesweeper。 为此,您不能将对象本身存储在数组中,因为这两种类型的对象可能大小不同并且具有不同的成员。 所以你可以有一个指向 Base 类的指针向量。 然后多态性部分用于识别,当您取消引用这些指针之一时,您是指向 Base 还是扫雷器。 虚函数用于根据它是哪个对象调用正确的函数。

您不能只将派生类对象的向量传递给需要基类对象向量的函数,因为向量不是从向量派生的。

你可以做一些转换,得到一片向量,像这样:

vector<Base> converted(base_vec.begin(), base_vec.end());

但这效率不高,如果调用方法在您的控制范围内,则可以使用模板:

template <typename T>
void foo(const vector<T>& v) {
    v[0].bar(); // do something with v
}

如果您不希望其他类型具有 bar 但不是 Base 的派生类,则可以使用 std::enable_if:

template<typename T, typename Enable=std::enable_if<std::is_base_of<Base, T>::value>>
void foo(const std::vector<T>& v) {
    v[0].bar(); // do something with v
}

整个程序可以用gcc main.cc -std=c++11编译:

#include <vector>

class Base{
public:
    void bar() const {}
};

class Derived: public Base{
};

template<typename T, typename Enable=std::enable_if<std::is_base_of<T, Base>::value>>
void foo(const std::vector<T>& v) {
    v[0].bar();
}

int main() {
    std::vector<Derived> a(1);
    foo(a);
}

您还可以将std::transformstd::back_inserter ,请参阅 [ https://stackoverflow.com/a/33522799/638048]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM