使用基类指针转换向量以返回子类

时间:2019-08-05 15:41:12

标签: c++ inheritance casting

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

使用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。编辑:稍微解释一下该问题发生的情况:下面的代码演示了该问题。实际的解析函数在不同的位置多次调用。

#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;
}

3 个答案:

答案 0 :(得分:2)

  

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

你不能。

让我尝试解释一下,如果编译器允许您这样做,那将是一个问题。假设您还有一个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。请注意,在使用virtual之前,您需要将基类更改为至少具有一个dynamic_cast成员函数。选择析构函数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. 保留派生类指针的向量。那么您不必担心转换。

答案 1 :(得分:1)

你不能。

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

答案 2 :(得分:0)

对于任何类模板:

template <typename T> class Foo;
就编译器而言,

Foo<T>Foo<U>是完全不具有转换关系的完全独立的类型,即使T和U相关。 (在这种情况下,T和U是指向base的指针,并且是派生的指针。)因此,std::vector<txt_specific *>std::vector<txt_base *>是无关的,并且您要执行的强制转换无效。在某些语言中,可以对相关元素的容器进行转换,但是在c ++中,不能。

如果您是模板类的作者,则可以在类中添加一些模板化的转换,但是标准库对vector并没有这样做。

唯一的方法是制作一个单独的容器并在插入它们时转换每个元素,或者仅使用原始容器并在要使用它们时向下转换它们。如果可以确保知道将其向下转换的正确类型,请使用static_cast。如果它是多态的,并且您不能事先确定,则应该使用dynamic_cast并验证是否获得了有效的(非null)指针结果。