Inheritance and STL containers
-
Let’s say I’m adding a derived class object to a vector that holds objects of base class type. STL vector allows me to do that without any explicit conversion. How do I revert the object inside a vector back to the derived class type? I’m only adding a pointer to the container not the actual object.
-
Let’s say I’m adding a derived class object to a vector that holds objects of base class type. STL vector allows me to do that without any explicit conversion. How do I revert the object inside a vector back to the derived class type? I’m only adding a pointer to the container not the actual object.
-
See this answer below: Re: Inheritance and arrays - C / C++ / MFC Discussion Boards[^].
So it works the same way. Got it.
-
Let’s say I’m adding a derived class object to a vector that holds objects of base class type. STL vector allows me to do that without any explicit conversion. How do I revert the object inside a vector back to the derived class type? I’m only adding a pointer to the container not the actual object.
Let me expand a bit on my previous answer[^]. As I said, you can convert a pointer (or reference) to pointer (or reference) to the base class. This called "upcasting" because you are moving "up" in the inheritance tree. The conversion is "non-destructive", in other words you can later on "downcast" (move from base to derived) as long as you know what type of object was in the first place. An example:
struct Unit {
Unit (int tag) : dog_tag(tag){};
virtual std::string kind () = 0;
int dog_tag;
};struct Soldier : public Unit {
Soldier (int tag) : Unit(tag) {};
virtual std::string kind() {return "soldier";};
float running_speed;
}struct Sailor : public Unit {
Sailor (int tag) : Unit(tag) {};
virtual std::string kind() {return "sailor";}
int life_jackets;
};std::vector actors {new Soldier(555), new Sailor(666);};
int main () {
Unit* u0 = actors[0];
std::cout << "Actor 0 is a " << u0.kind() " with tag " << u0.dog_tag << std::endl;If you would look with a debugger at
u0
you would see a memory layout something like this:
u0 0x1234 -------> pointer to vtable of Soldier dog_tag ----------------------------- running_speed ------------------------------
You can see now why the code works: no matter what kind of object you deal with, the first part of the memory layout is the same. Compiler simply ignores whatever is after the
dog_tag
field. A few more lines of code (please ignore that I didn't initialize other fields):Soldier *s = (Soldier *)u0;
std::cout << "Running speed " << s->running_speed << std::endl;s
has exactly the same value asu0
but compiler considers it a pointer to aSoldier
object so it uses the value from therunning_speed
field. I could have written:Sailor *ss = (Sailor*)u0;
std::cout << "Sailor has " << ss->life_jackets << " life jackets";And compiler wouldn't have cared at all. It would have accessed the memory at
lif