-3

I'm having real trouble to figure out this casting problem. Starting with 3 classes:

#include <vector>
// Pure virtual class
class Base1{
  public:
   virtual ~Base1();
   virtual void do_sth()=0;
}
class Base2{
  public:
   int prop=3;
   ~Base2();
}
class Derived: public Base1, Base2{
  ~Derived();
  void do_sth(){print("Hi");};
}

How can I perform the following conversion?

std::vector<Base1*> vec1
vec1.reserve(10);
for( int i = 0; i < 10; ++i )
    vec1.push_back(new Derived());

// To this type...?
std::vector<Base2*> vec2 = ?????;

Some remarks:

  • I'd use dynamic_cast to perform safe casting from Base1 to Derived.
  • Ideally, no object copies are made in the process!.
  • My best bet so far is to call vec2.data() to obtain a Base1* pointer, then dynamic_cast to Derived, then static cast to Base2, but I don't know how to transfer memory ownership nor how to pass vector size.
ibarrond
  • 6,617
  • 4
  • 26
  • 45
  • 2
    Base1 and Base2 are not related, so this is an illegal operation. Even if you stored Derived objects in there, due to object slicing only the Base1 member is pushed into the vector. – Botje Sep 07 '21 at 14:02
  • _"How can I perform the following conversion?"_. Such a conversion would be meaningless. What are you hoping to get in `vec2`? You may need to describe what you are attempting to get a reasonable answer. – Drew Dormann Sep 07 '21 at 14:05
  • @DrewDormann I'm calling an external function that requires a vector of type Base2, and I have a vector of type Base1 to begin with. It might not be very helpful to know this. – ibarrond Sep 07 '21 at 14:08
  • @Botje I'm ok with slicing, I don't plan to revert back to Derived or Base1. – ibarrond Sep 07 '21 at 14:10
  • @ibarrond did you create `Derived` as an attempt to solve this problem? This may be an [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). – Drew Dormann Sep 07 '21 at 14:10
  • Also, the "no copies" requirement is impossible: `static_cast(&aDerivedObject)` and `static_cast(&aDerivedObject)` will result in different memory addresses. – Botje Sep 07 '21 at 14:10
  • @DrewDormann Not particularly, Derived is an implementation of Base1, which happens to be a pure virtual class. However, I'm not fully convinced about the design choice anymore. It might end up being subject to a separate question. Let me check your XY reference – ibarrond Sep 07 '21 at 14:14
  • @Botje can you elaborate? I'm honestly curious about it. – ibarrond Sep 07 '21 at 14:15
  • 1
    You're adding conditions based on your misunderstanding of the basic issues. Start with how to store a vector of base class pointers. You probably need more of a basis than you can get from SQ questions, but you could start with https://stackoverflow.com/questions/18223036/i-want-a-vector-of-derived-class-pointers-as-base-class-pointers And that doesn't even mention virtual destructors. Hmm – Kenny Ostrom Sep 07 '21 at 14:18
  • Assuming Base1 and Base2 have a few member variables each, code that receives a `Base2*` expects its first member variable to start at a certain offset from the pointer. If you are passing it a Derived* then the compiler will actually pass a pointer to the start of the Base2 member, which is different from the start from a Base1 member. – Botje Sep 07 '21 at 14:19
  • @Botje kill me for it, and I am seriously considering a separate SO question about my architectural choice, but Base1 actually has no member variables. Base2 does, and quite a few. – ibarrond Sep 07 '21 at 14:22
  • 1
    I have no idea how you expected that to work. Of course it doesn't help that your question is _extremely_ vague to the point of being unanswerable. – Botje Sep 07 '21 at 14:25
  • There's no answer. Because there is no way to inspect a `Base1` object, with no member variables, and determine how to convert it to a `Base2` object with "quite a few" member variables. Not with the code shown here. If you had tried the `dynamic_cast` you suggested, you would see that it always fails. – Drew Dormann Sep 07 '21 at 14:25
  • @Botje I naively thought it could be possible. Based on the comments, I guess it is not possible. – ibarrond Sep 07 '21 at 14:29
  • Should I erase the question? I wasn't expecting so many negative votes, but I guess they are justified. I already got my answer, and if noone will benefit from it, it might be better to delete it. – ibarrond Sep 09 '21 at 08:29

2 Answers2

1

There are no Derived objects in vec1 nor vec2, so you can't get pointers to other base subobjects of a Derived from an element of either.

If pass a Derived to vec1.push_back, it will copy-construct a Base1 from the Base1 subobject of the Derived. This is called object slicing.

If you have a vector of pointers (raw or smart) to Base1 in vec1, then those could point to the Base1 base subobject of a Derived, at which point you can dynamic_cast<Base2*> them, which will in general give you a different pointer value.

Caleth
  • 52,200
  • 2
  • 44
  • 75
  • Thanks! Recipe for success: always treat vectors of pointers and copy them. It is fast, it is cleaner, there are still checks in place, like here: https://stackoverflow.com/questions/29494590/ . For the Base1 -> Derived, either avoid or dynamic_cast to Derived* into a new vector (individual casting). – ibarrond Sep 07 '21 at 15:12
1

The comments to the question have gotten rather muddled, so I'll post this partial answer here, rather than trying to straighten out the comments.

Base1 has a virtual function. Good start.

Derived is derived from Base1.

Derived is also derived from Base2.

If you have an object of type Derived you can create a pointer to Base1 that points at the derived object:

Derived d;
Base1* b1 = &d;

Now that you have a pointer to a polymorphic base class, you can use dynamic_cast to perform a cross-cast:

Base2* b2 = dynamic_cast<Base2*>(b1);

The compiler knows how to do that, and the result should be the same pointer value as you'd have gotten if you did it directly:

Base2* b2x = &d;
assert(b2x == b2);

Note, too, that since the code traffics in vectors of pointers, it seems that the Derived objects are being created with new Derived. If that's the case, and eventually the code deletes the Derived object through a pointer to one of the base types, then the base type must have a virtual destructor.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
  • Thanks! I ended up doing exactly this! I looped through the first vector and performed direct `dynamic_cast` over the elements. – ibarrond Sep 08 '21 at 08:50