I have a problem I am working on. I have a number classes which inherit each other in this pattern:
#include <stdio.h>
#include <stdlib.h>
#include <list>
class TimeObject
{
public:
virtual void Tick()=0;
std::list<TimeObject*> ticks;
};
class MapObject : public TimeObject
{
public:
MapObject()
{
ticks.push_front(this);
printf("Create MapObject %p\n", this);
}
void Tick() { printf("mapobject tick\n"); }
};
class ControlObject : public MapObject
{
public:
ControlObject()
{
ticks.push_front(this);
printf("Create ControlObject %p\n", this);
}
void Tick() { printf("controlobject tick\n"); }
};
int main()
{
ControlObject test;
std::list<TimeObject*>::iterator it = test.ticks.begin();
for(; it != test.ticks.end(); it++)
{
TimeObject *trigger = *it;
trigger->Tick();
}
return 0;
}
The list in the example stores any TimeObject derived class. My problem is that when storing MapObject pointers in the list that are also ControlObjects dispatch always picks the ControlObject function.
Is it possible to trigger the MapObject function with a ControlObject pointer using polymorphism? If it isn’t possible/pratical, what would be a good alternative?
You should always store pointer to the Base class
A*in the list(std::list< A*>).The pointer should be correctly made to point either a object of type
BorCbefore you add the pointer to the container.Once you do that, dynamic dispatch will take care of calling the correct function for you depending on the actual object type. You don’t need to do anything.
I don’t know why you want to have any design which is otherwise, If you have any good reasons to do so please let know of them.
Why it always calls
ControlObject::tick()in your code?When you call:
in
ControlObject::ControlObject()you basically end up overwriting the first pointer you added to the list, The type of the first pushed pointer is notMapObject *anymore it isControlObject *because you changed the pointer behind its back.You did not transfer ownership of the pointer to the list but you both had shared ownership and you modified the object in your list through the constructor call in derived class. This leaves you with twoControlObject *objects in the list which dynamic dispatch correctly determines and calls the correct method.There is nothing wrong in what dynamic dispatch does, it is the correct behavior.
If you want to call
MapObject::Tick();then you will explicitly have to tell the compiler to do so, dynamic dispatch works on the actual type of object and it is working correctly.Replicating from the comments: