简体   繁体   中英

Cast vector with base class pointers to back to subclass

I want to cast a vector of base class pointers to a vector of subclass pointers. As far as I understand it, object slicing does not apply here because the vector consists of pointers.

Casting a single object with txt_specific *o = (txt_specific *) x.front(); works but I cannot figure out how to cast the whole vector at once.

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

EDIT : I tried the answer from this question but it does not seem to work.

2. EDIT : To explain a bit the situation in which that problem occurred: This code below demonstrates it. The actual parse function is called several times in different places.

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

I want to cast a vector of base class pointers to a vector of subclass pointers.

You can't.

Let me try to explain why that would be a problem if the compiler let you do that. Let's say you have another class derived from 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.
}

Casting a single object with txt_specific *o = (txt_specific *) x.front(); works but I cannot figure out how to cast the whole vector at once.

I hope I have explained why you should not attempt to do that. The choices for you are:

  1. Get a pointer to the base class and then perform a dynamic_cast . Please note that you'll need to change the base class to have at least one virtual member function before using dynamic_cast . Making the destructor virtual is the easiest choice. It is also appropriate when you want to delete derived class objects using a base class pointer.

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

    and

     txt_base* ptr = x.front(); txt_specific* o = dynamic_cast<txt_specific *>(ptr); if ( o != nullptr ) { // Use o } 
  2. Keep a vector of derived class pointers. Then you don't have to worry about casting.

You can't.

A vector of one thing is not pointer-compatible with a vector of some other thing.

For any class template:

template <typename T> class Foo;

Foo<T> and Foo<U> are, as far as the compiler is concerned, completely separate types that have no conversion relationship at all, even if T and U are related . (In this case, T and U are pointer to base and pointer to derived.) Thus, std::vector<txt_specific *> and std::vector<txt_base *> are unrelated, and the cast you want to do is invalid. In some languages you can do the conversion on a container of related elements, but in c++ you cannot.

If you are a template class author you can add some templated conversions into your class, but the standard library did not do this for vector.

The only way is to make a separate container and convert each element as you insert them, or merely use the original container and downcast them as you're about to use them. If you are guaranteed to know the correct type to downcast it to, then use static_cast. If it's polymorphic and you cannot be sure in advance, you should use dynamic_cast and verify you get a valid (non-null) pointer result.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM