我有一个基类:
class Member
{
....
}
和派生类,如下所示:
class Mine_sweeper : private Member
{
....
}
然后我有一个容器:
class Population
{
public:
std::vector<Member>& m_members;
Population(std::vector<Member>& members);
}
当我使用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 &'
答案 0 :(得分:2)
你做不到。不是这样的。这是因为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
来处理内存所有权。
答案 1 :(得分:1)
Population类的构造函数接受一个包含Member类数组的向量的参数。你是对的,你可以将派生类传递给以基类为参数,或者从派生到基础的upcast,但你在这里做的是不同的。你没有将派生类发送给一个带有基类参数的函数,你要发送一个不同的无关类型,你发送一个std :: vector&lt;的typeA&GT;想要std :: vector&lt;的TypeB取代。
当你创建std :: vector&lt; INT&GT;在编译时,它将创建向量类,其中包含特定于其如何迭代整数等的所有特定细节。这是一个数组或“整数”。将它传递给一个带有双精度数组的函数是否有意义?然后该函数正在对双精度进行操作,例如,为了移动到下一个双精度,它可能向前移动8个字节而不是4个,这将是错误的。
您必须手动创建两个版本的Population类,或使用模板执行此操作。编辑:看YSC的答案,他模板构造函数
或者,你可能想要一个矢量/数组,它可以包含两种类型的类,Base和Minesweeper。为此,您无法将对象本身存储在数组中,因为这两种类型的对象可能大小不同并且具有不同的成员。所以你可以有一个指向Base类的指针。然后,当您取消引用其中一个指针时,多态性部分用于识别您是指向Base还是Minesweeper。虚函数用于根据对象调用正确的函数。
答案 2 :(得分:1)
Mine_sweepers的矢量不是会员的“类型”矢量,即使Mine_sweeper是“一种”会员。您无法使用vector<Derived>
代替vector<Base>
。
使用vector<unique_ptr<Member>>
代替vector<Member>
和vector<Mine_sweeper>
。这使您可以拥有异构的成员群体(即Mine_sweepers和其他成员子类型,同时)。
或者,将Population类转换为类模板:
class Population<T>
{
public:
std::vector<T>& m_members;
Population(std::vector<T>& members);
}
这样,一个Population实例可能只包含一种类型的成员。
答案 3 :(得分:0)
您不能仅将派生类对象的向量传递给需要基类对象向量的函数,因为向量不是从向量派生的。
您可以做一些掩饰,得到矢量的一部分,像这样:
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);
}
答案 4 :(得分:0)
您也可以将std::transform
与std::back_inserter
一起使用,请参见[https://stackoverflow.com/a/33522799/638048]