我正在解决一个问题。我有一个数字类,它们以这种模式相互继承:

#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;
}


示例中的列表存储任何TimeObject派生类。我的问题是,将MapObject指针存储在也是ControlObjects分派的列表中时,总是会选择ControlObject函数。

是否可以使用多态性用MapObject指针触发ControlObject函数?如果不可能/不切实际,那么什么是不错的选择?

最佳答案

您应该始终将指向基类A*的指针存储在列表(std::list< A*>)中。
在将指针添加到容器之前,应正确地使指针指向BC类型的对象。
一旦这样做,动态分派将根据实际的对象类型来为您调用正确的函数。您什么都不需要做。

我不知道您为什么要拥有其他设计,如果您有充分的理由这样做,请告知他们。

为什么它总是在代码中调用ControlObject::tick()
您打电话的时候:

ticks.push_front(this);


ControlObject::ControlObject()中,您基本上最终会覆盖添加到列表中的第一个指针,第一个被推入的指针的类型不再是MapObject *,因为它已更改了其后面的指针,因此不再是ControlObject *。您没有转让所有权指向列表的指针,但是你们两个都有共享的所有权,并且通过派生类中的构造函数调用修改了列表中的对象。这使您在列表中留下两个ControlObject *对象,动态分派可以正确地确定并调用正确的方法。

动态调度的工作没有错,这是正确的行为。
如果要调用MapObject::Tick();,则必须明确告知编译器执行此操作,动态分派将在对象的实际类型上起作用,并且工作正常。

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




从评论中复制:


  恐怕这是一个糟糕的设计。代码按其应有的方式工作,如C ++标准所定义的那样工作。问题出在设计上。并且除非您提供广义上要实现的目标的详细信息,否则,它是不正确的。很难推测新设计。

关于c++ - 多态性确定问题,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10713702/

10-12 14:24