试图从 Derived* 的向量中分配 Base* 的向量

Posted

技术标签:

【中文标题】试图从 Derived* 的向量中分配 Base* 的向量【英文标题】:Trying to assign vector of Base* from vector of Derived* 【发布时间】:2015-04-07 14:52:40 【问题描述】:

这似乎是一个非常基本的问题,但我无法弄清楚。我有一个指向派生对象的原始指针std::vector,我只想使用赋值运算符将它复制到另一个基指针向量。使用 VC++ 我得到错误 C2679 "binary '=': no operator found..." BTW 我不想要对象的深层副本,我只想复制指针。示例代码:

#include <vector>
using namespace std;

struct Base;    
struct Derived: public Base ;

int main (int argc, char* argv[])

    vector<Derived*> V1;
    vector<Base*> V2;
    V2 = V1;  //Compiler error here
    return 0;

让我感到困惑的是,我可以通过循环并使用push_back 来复制向量,如下所示:

for (Derived* p_derived : V1)
    V2.push_back(p_derived);

所以我的问题是为什么分配失败,而 push_back 有效?对我来说似乎是同样的事情。

【问题讨论】:

【参考方案1】:

这是因为虽然BaseDerived 有关系,但vector&lt;Base*&gt;vector&lt;Derived*&gt; 之间没有关系。就类层次结构而言,它们完全不相关,因此您不能将一个分配给另一个。

您正在寻找的概念称为covariance。例如,在 Java 中,String[]Object[] 的子类型。但在 C++ 中,这两种类型只是不同的类型,与String[]Bar 没有更多的相关性。

push_back 有效,因为该方法只需要T const&amp;(或T&amp;&amp;),因此任何可转换为Base* 的东西都是可以接受的——Derived* 就是这样。

也就是说,vector 有一个带有一对迭代器的构造函数,在这里应该更容易使用:

vector<Base*> v2(v1.begin(), v1.end());

或者,因为它已经构建好了:

v2.assign(v1.begin(), v1.end());

【讨论】:

我想如果赋值运算符必须接受不同但相关类型的向量,它会变得过于复杂。 这也是一个(很常见的)C++ FAQ。见this。 在 C# 中,List&lt;Base&gt; 也与 List&lt;Derived&gt; 无关,但 IEnumerable&lt;Base&gt;IEnumerable&lt;Derived&gt; 的子类型,因为 IEnumerable 是变体。 @usr co变体。按照常见问题解答示例,这不会违反类型安全,因为IEnumerable&lt;T&gt; 是只读接口,因此您不能破坏vector&lt;Apple*&gt;。但是,可以想象在一个系统中,vector&lt;T&gt; 仍然是不变的,但存在一个 const_vector&lt;T&gt;,它可能是协变的。【参考方案2】:

push_back 执行元素转换。赋值运算符只存在于相同类型的向量之间。

一个简单的解决方案是使用assign

v2.assign(v1.begin(), v1.end());

【讨论】:

【参考方案3】:

在模板的一般情况下,如果你有一个类模板

template <typename T> struct Foo ;

Foo&lt;Base&gt; 不是Foo&lt;Derived&gt; 的基类。

因此,你不能这样做:

Foo<Derived> f1;
Foo<Base> f2 = f1;

【讨论】:

以上是关于试图从 Derived* 的向量中分配 Base* 的向量的主要内容,如果未能解决你的问题,请参考以下文章

在向量中分配临时元素(知道最大数量)的最快方法?

在私有继承中公开构造函数

向量和派生向量类之间的区别

无法从Base转换为Derived

如何从 Derived 内部调用 Base 实例中的受保护成员函数?

将派生类指针的向量传递给线程