![](/img/trans.png)
[英]C++ How to set a pointer of type std::vector<Derived*> to object of type std::vector<Base*>
[英]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);
}
一种解决方案是使用现有的从B
到A
隐式转换提供显式转换:
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_ptr
、 std::shared_ptr
和std::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::transform
与std::back_inserter
,请参阅 [ https://stackoverflow.com/a/33522799/638048]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.