【问题标题】:Making a pointer to std::vector of base class pointers point to std::vector of derived class pointers使指向基类指针的 std::vector 的指针指向派生类指针的 std::vector
【发布时间】:2016-02-19 02:17:47
【问题描述】:

为冗长的标题道歉。我不知道如何简洁地表达这一点。

class A 
{
      bool a1; 
      unsigned int a2 ; 
      virtual bool aFn1(unsigned int t_) = 0 ; 
      virtual void aFn2(unsigned int t_, bool val_) = 0 ;  
      A() 
      {
           a1 = false ; a2 = 0 ; 
      };
}

下一个:

#include <bitset> 
#define MAX_SIZE 500 

class B : public class A 
{
  private: 
     std::bitset<MAX_SIZE> _bmem; 
  public:
     B() : A() {}; 
     using A::aFn1 ;            
     virtual bool aFn1(unsigned int t_) 
        {
           return _bemem[t_] 
        } 
      using A::aFn2;
     virtual void aFn2(unsigned int t_, bool val_)
     {
        _bemem[t_] = val_ ; 

     }
}

下一个:

#include "A.h"
#include "B.h"

std::vector<A*> * vecA; 
vecA = new std::vector<B*> ; 

但这最后一步不起作用。铿锵完整告诉我

从不兼容的类型std::vector&lt;B*&gt; 分配给std::vector&lt;A*&gt; *

但是由于B 派生自A,这应该是可能的吧?我见过人们使用的例子

B bObj;
A *aObj = &bObj ;

那么你能告诉我我犯了什么错误吗?

我之所以经历这一切,是因为我有class Cclass D,和class B 完全一样,唯一的区别是#define MAX_SIZE 不同。

我这样做是因为,我需要一个不同大小的bitset,以便在程序的不同阶段使用。而bitset 需要在编译时需要存储的元素数量。

【问题讨论】:

  • B 派生自A 并不意味着vector&lt;B*&gt; * 可以转换为vector&lt;A*&gt; *,它们是完全不相关的类型。为什么需要在vecA 中存储vector&lt;B*&gt; *?你到底为什么要new@vectorA 需要有一个 virtual 析构函数,并查看 unique_ptr,因为您使用的是 C++11。
  • @Praetorian 你能告诉我为什么我不应该新建一个向量吗?
  • @Praetorian 我需要创建至少一百万个这样的对象。它们被用作另一个类的私有成员。所以我在想可能是使用 unique_ptr 会导致性能下降。我在使用指针时小心使用 RAII。
  • A vector 已经为其内容动态分配内存并为您管理该内存,您极不可能需要动态分配vector 本身。 new 不应该在 C++ 中随意使用,将其视为一个非常专业的工具,只有在您确切知道自己在做什么时才应该使用它。关于你添加的解释,为什么不把bitset中的元素个数作为模板参数呢?
  • 您是否有任何证据支持这种性能下降的说法?带有默认删除器的unique_ptr 实际上与自己管理指针相同,并且它可以防止您在每一次转弯时都在踢自己的脚。

标签: c++ pointers c++11 vector new-operator


【解决方案1】:

你使用了太多的接口和指针。

class A  {
  bool a1 = false; 
  unsigned int a2 = 0; 
  std::vector<bool> values;
  bool aFn1(unsigned int t_) const { return values[t_]; }
  void aFn2(unsigned int t_, bool val_) { values[t_] = val_; }
  void set_size(size_t i){values.resize(i);}
  A() = default;
  static A of_size(size_t i){ A r; r.set_size(i); return r; }
};

然后使用std::vector&lt;A&gt;

如果您有 100 个大小为 500 的元素,请执行 std::vector&lt;A&gt; v( 100, A::of_size(500) );

与您的代码相比,此代码将执行更少的分配、使用更少的内存并且具有更少的间接性。使用new 是“代码异味”,通常表明你犯了错误,除非你真的需要寿命极其复杂的对象。

std::vector&lt;bool&gt; values 几乎和std::bitset&lt;500&gt; 一样紧凑,差异由我删除的其他指针弥补。

【讨论】:

  • 谢谢。我在这里看到了很多有趣的事情。我最初使用 std::vector ,但后来我切换到 std::bitset 因为它占用的空间更少。我需要这些位,我有超过一百万个项目,每个项目都有一个 bitset 。另外我可能必须在嵌入式中运行它。使用 const 有什么性能优势吗?
  • 你能解释一下最后两行的作用吗?
  • A() = 默认;告诉使用默认构造函数?我不知道。我怎样才能像你一样学习写 CPP?
  • 是的,我需要以特定方式使用对象,我正在创建类似于神经网络的东西,所以我需要灵活地传递指针等。
  • @nnrales std::vector&lt;bool&gt; 打包了它的元素。它不存储 1 个字节 bools (这实际上是一个问题,但在您的情况下,这意味着您不妨使用它)。 bitset 可以将其存储在本地,而 std::vector&lt;bool&gt; 必须存储在免费存储中,但是您的设计迫使您将其存储在类型作为指针中;我的可以让您将A-as-values 向下存储一层。这弥补了这一点。最后两行? A() = defaultA 声明一个默认构造函数;我在声明它们时初始化了a1a2static A of_size 是帮助轻松创建 500 个元素 As。
【解决方案2】:

您不能将std::vector&lt;A*&gt;* 指向std::vector&lt;B*&gt;*,它们是不同的类型。

可以做的就是将B* 推入std::vector&lt;A*&gt;

std::vector<A*> vec;
B b;
vec.push_back(&b);

当然,您需要注意指针的生命周期。如果向量应该自己管理生命周期,您可能需要使用 std::unique_ptr

还要注意A需要一个虚拟析构函数,否则通过A*删除B*是未定义的行为。

【讨论】:

  • 有没有其他方法可以做到这一点。我将不得不更改代码的主要部分才能使用它。我在其他函数中使用指向 A 的指针,并且更改它会有点不简单。
  • @nnrales 你仍然可以使用A*,这就是重点。 B* 隐式转换为 A*
【解决方案3】:

clang 完成告诉我assigning to std::vector&lt;A*&gt; * from incompatible type...

Clang 告诉你真相。

但既然 B 是从 A 派生的,这应该是可能的吧?

不对。

我见过人们使用的例子

B bObj;
A *aObj = &bObj ;

这些例子是正确的。它们之所以起作用,是因为AB 的父级。子类的指针可以转换为父类的指针。

那么你能告诉我我犯了什么错误吗?

您正在尝试将指向 std::vector&lt;B*&gt; 的指针分配给指向 std::vector&lt;A*&gt; 的指针。 std::vector&lt;A*&gt; 不是 std::vector&lt;B*&gt; 的父级。在继承方面,它们是完全不相关的类。指向类型的指针不能转换为指向不相关类型的指针。

【讨论】:

  • 既然我在 std::vector 中使用 A 和 B ,继承不再成立?但另一方面,A 是 B 的父级。我想我明白为什么会这样,std::vector 将为 A 成员分配空间,但 B 不适合该空间。
  • 我希望你明白我想要做什么。我想要一个基类的 std::vector ,用派生类的 std::vector 代替。有没有办法做到这一点?
  • @nnrales 被派生类的 std::vector 替换是什么意思
  • @我有一个 for 循环,它通过 std::vector 的 A 。有没有办法在 for 循环中使用 B 的 std::vector 。或者我有一个函数,它需要一个指向 A 的 std::vector 的指针,有没有办法在它的位置使用指向 B 的 std::vector 的指针?
  • @nnrales 不,你不能。但是您可以轻松地将循环更改为通过 B 的向量而不是 A 的向量。如果您想将其他导数传递给该函数,则该函数会比较棘手。如果您不需要运行时多态,那么模板可能是更适合您的解决方案。
【解决方案4】:

这归结为

std::vector<Base*> *v = new std::vector<Derived*>;

std::vector&lt;Base*&gt;std::vector&lt;Derived*&gt; 不是兼容的类型,原因与您不能将Derived* 的数组用作Base* 的数组相同。

比如上面写v-&gt;push_back(new Base())会怎么样?您的Derived* 向量中不能有Base*

有关将Derived* 视为Base* 所涉及的问题的详细解释,另请参阅this answer to "Converting std::function&lt;void(Derived*)&gt; to std::function&lt;void(Base*)&gt;" 背后的推理,这是同一问题的不同形式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-02-17
    • 1970-01-01
    • 2015-11-05
    • 2011-03-18
    • 2012-04-19
    • 1970-01-01
    • 2016-03-15
    相关资源
    最近更新 更多