【问题标题】:Cast vector with base class pointers to back to subclass将带有基类指针的向量转换回子类
【发布时间】:2019-12-13 04:10:05
【问题描述】:

我想将基类指针向量转换为子类指针向量。据我了解,对象切片在这里不适用,因为向量由指针组成。

使用txt_specific *o = (txt_specific *) x.front(); 投射单个对象有效,但我不知道如何一次投射整个向量。

#include <vector>

class txt_base {
  int a;
};

class txt_specific : public txt_base {
  int b;

  void do_stuff(){};
};

int main() {
  std::vector<txt_base *> x {new txt_specific()};

  // This cast does not work
  std::vector<txt_specific *> y = (std::vector<txt_specific *>) x;

  return 0;
}

编辑:我尝试了this question 的答案,但似乎不起作用。

2。编辑:解释一下发生该问题的情况:下面的代码演示了它。实际的 parse 函数在不同的地方被多次调用。

#include <vector>

class txt_base {};
class txt_specific1 : public txt_base {};
class txt_specific2 : public txt_base {};

enum t {
  TYPE1,
  TYPE2
};

void parser1(std::vector<txt_specific1 *> vec) {}
void parser2(std::vector<txt_specific2 *> vec) {}

void parse(std::vector<txt_base *> &x, t type) {
  // the cast would be needed in this function
  switch (type){
    case TYPE1: parser1(x); break;
    case TYPE2: parser2(x); break;
  }
}

int main() {
  std::vector<txt_base *> x {new txt_specific1()};
  parse(x, TYPE1);

  return 0;
}

【问题讨论】:

  • 您不能一次投射整个向量。无论 X 和 Y 是什么,vector 都不能转换为 vector。真正的问题是您为什么要这样做,您要解决什么问题?
  • 你不能,你也不需要它。
  • 您可能不想转换用户定义类的对象。
  • “但它似乎不起作用” 以什么方式?做什么?你没有告诉我们你想做什么。只有你认为你想做的事情。
  • 带有基类指针的向量被传递给函数。然后,此函数根据通过不同参数知道的 txt 类型(子类)调用不同的解析器

标签: c++ inheritance casting


【解决方案1】:

我想将基类指针向量转换为子类指针向量。

你不能。

让我试着解释一下,如果编译器允许你这样做,为什么会出现问题。假设您有另一个派生自 txt_base 的类。

#include <vector>

class txt_base {
  int a;
};

class txt_specific : public txt_base {
  int b;

  void do_stuff(){};
};

class txt_utf8 : public txt_base {
  // ...
  // Member data
  // ...

  void do_stuff(){};
};

int main() {
  std::vector<txt_base *> x {new txt_specific(), new text_utf8()};

  // Let's say te compiler allowed this
  std::vector<txt_specific *> y = (std::vector<txt_specific *>) x;

  txt_specific* ptr = y[1];
  // Now you have ptr of type txt_specific that really points to a txt_utf8.
  // Dereferencing ptr and using it member variables and member functions will 
  // lead to undefined behavior.
}

使用txt_specific *o = (txt_specific *) x.front(); 投射单个对象有效,但我不知道如何一次投射整个向量。

我希望我已经解释了为什么你不应该尝试这样做。您的选择是:

  1. 获取指向基类的指针,然后执行dynamic_cast。请注意,在使用dynamic_cast 之前,您需要将基类更改为至少具有一个virtual 成员函数。制作析构函数virtual 是最简单的选择。当您想使用基类指针删除派生类对象时,它也是合适的。

    class txt_base {
      public:
         virtual ~txt_base() {}
    
      private:
         int a;
    };
    

    txt_base* ptr = x.front();
    txt_specific* o = dynamic_cast<txt_specific *>(ptr);
    if ( o != nullptr )
    {
       // Use o
    }
    
  2. 保留一个派生类指针向量。那么你就不用担心投射了。

【讨论】:

  • 感谢您的详细解释。我确实理解为什么它会导致未定义的行为。关键是我知道向量中的所有元素都具有相同的类型,我认为也许可以进行强制转换
  • @elya5 如果你真的提前知道类型,我敢肯定有办法改变代码,让它仍然是通用的,你没有硬编码的类型,比如基类.
【解决方案2】:

你不能。

一个事物的向量与其他事物的向量不兼容。

【讨论】:

  • @MaxLanghof,虽然您标记为重复的帖子与主题密切相关,但问题的症结并不相同。在那篇文章中,OP希望自动将设备类指针向量转换为基类指针向量。在这篇文章中,OP 希望自动将基类指针向量转换为派生类指针向量。这是一个非常微妙但重要的区别。
  • 你说得对,下次我会小心的。虽然我仍然怀疑你在 1 分钟内验证了没有欺骗目标;)
  • 当我注意到问题已关闭时,我正在回答。当我重新打开问题时,SO 已经保存了我的答案 :) 我没有重新打开问题只是为了能够发布我的答案。
【解决方案3】:

对于任何类模板:

template <typename T> class Foo;

Foo&lt;T&gt;Foo&lt;U&gt; 对于编译器而言,是完全分离的类型,根本没有转换关系,即使 T 和 U 相关时间>。 (在这种情况下,T 和 U 是指向基址的指针和指向派生的指针。)因此,std::vector&lt;txt_specific *&gt;std::vector&lt;txt_base *&gt; 是不相关的,并且您想要做的转换是无效的。在某些语言中,您可以在相关元素的容器上进行转换,但在 c++ 中则不能。

如果您是模板类作者,您可以将一些模板化转换添加到您的类中,但标准库没有为矢量执行此操作。

唯一的方法是制作一个单独的容器并在插入每个元素时对其进行转换,或者仅使用原始容器并在您将要使用它们时向下转换它们。如果您保证知道将其向下转换为的正确类型,请使用 static_cast。如果它是多态的并且你不能提前确定,你应该使用 dynamic_cast 并验证你得到一个有效的(非空)指针结果。

【讨论】:

    猜你喜欢
    • 2015-08-12
    • 1970-01-01
    • 1970-01-01
    • 2021-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多