0

我有一个正在处理的问题。我有一个以这种模式相互继承的数字类:

#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如果不可能/不切实际,有什么好的选择?

4

3 回答 3

2

您应该始终将指向 Base 类的指针存储A*在 list( 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++ 标准的定义工作。问题在于设计。除非您提供更广泛意义上的目标细节推测一个新的设计是困难的,而且毫无意义。

于 2012-05-23T05:05:04.260 回答
0

将类型 C 的变量转换为类型 B 应该可以解决问题。

   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();
于 2012-05-23T05:06:13.143 回答
0

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(); }
};

显式函数调用表示法是必需的。

于 2012-05-23T05:57:43.497 回答