The way c++ places classes in memory is to put the base class first then derived class information after that.
|base class|derived class|
^ ^ ^
a b c
If you took the address of one of these objects that would be memory address a
, the end of the class is at address c
in this diagram. The information in your derived class is in the memory segment from b
to c
. There's 2 versions of apply
stored in the memory here: a version for the base class and one for the derived class which one gets called is based on the type of the object.
When you create an array with Effect effects[3]
for example you get memory that looks like this:
|effect|effect|effect|
C++ just allocates you just enough space to fit an effect
class per array index and no more.
Now the problem is that you try to place and object that looks like this into the first element of the array:
|effect|somesubclass|
This can't fit into one array element so c++ slices off the end of the class, which includes the information about the subclass to put it in the array which loses information. Any members of the derived class are now gone! The array is of type effect
so anything placed in the array will be treated as though it were that type and methods will be called accordingly. This then causes problems like the one you encountered.
This is known as the slicing problem: What is object slicing?
To deal with this you should never use a polymorphic array of objects, instead use pointers to the objects because the pointers are all the same size and hence will properly work when used inside the array. A pointer to the base class will be the same size as a pointer to the derived class, it's just the pointer to the start of the memory block after all. The pointers will now point to the correct type and hence the correct versions of functions will be called.