简体   繁体   中英

Polymorphism determination issue

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 B or C before 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:

ticks.push_front(this); 

in ControlObject::ControlObject() you basically end up overwriting the first pointer you added to the list, The type of the first pushed pointer is not MapObject * anymore it is ControlObject * 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 two ControlObject * 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.

void controlobject::Tick() 
{ 
    printf("controlobject tick\n"); 
    MapObject::Tick();
}

Replicating from the comments:

I am afraid this is a bad design.The code works as it should,it works as defined by the C++ standard.The problem lies in the design.And unless you provide the details of what you are trying to achieve in a broader sense it is difficult and rather pointless to speculate on a new design.

Using a cast on the variable of type C to the type B should do the trick.

   C c;
   B b;
   c.Function();
   ((B)c).Function();
   A * l[] = {&c,&b,&c};
   l[0]->Function();
   l[1]->Function();
   l[2]->Function();

   B test = *(B*)l[0];
   test.Function();

In your current example you should be able to call both virtual members (or just the one depending on the underlying type) by calling MapObject::Tick() inside ControlObject::Tick() :

class ControlObject : public MapObject
{
  public:
    ControlObject()
    {
        ticks.push_front(this);

        printf("Create ControlObject %p\n", this);
    }

    void Tick() { printf("controlobject tick\n"); MapObject::Tick(); }
};

The explicit function call notation is required.

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