多态性确定问题

Polymorphism determination issue

本文关键字:问题 多态性      更新时间:2023-10-16

我有一个问题正在处理。 我有一个数字类,它们在此模式下相互继承:

#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 %pn", this);
    }
    void Tick() { printf("mapobject tickn"); }
};
class ControlObject : public MapObject
{
  public:
    ControlObject()
    {
        ticks.push_front(this);
        printf("Create ControlObject %pn", this);
    }
    void Tick() { printf("controlobject tickn"); }
};
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函数。

是否可以使用多态性使用ControlObject指针触发MapObject函数? 如果不可能/不切实际,那会是一个好的选择吗?

您应该始终在列表( std::list< A*> )中存储指向基类A*的指针。
在将指针添加到容器之前,应正确使指针指向类型为 BC 的对象。
完成此操作后,动态调度将根据实际对象类型为您调用正确的函数。你不需要做任何事情。

我不知道你为什么要有任何设计,如果你有任何充分的理由这样做,请告诉我。

为什么它总是在你的代码中调用ControlObject::tick()
当您致电时:

ticks.push_front(this); 

ControlObject::ControlObject()你基本上最终覆盖了你添加到列表中的第一个指针,第一个推送指针的类型不再MapObject *ControlObject *,因为你在背后更改了指针。您没有将指针的所有权转移到列表,但你们都拥有共享所有权,并且通过派生类中的构造函数调用修改了列表中的对象。这在列表中留下了两个ControlObject *对象,动态调度正确确定并调用正确的方法。

动态调度没有错,这是正确的行为。
如果要调用MapObject::Tick();那么必须显式告诉编译器这样做,动态调度适用于对象的实际类型并且工作正常。

void controlobject::Tick() 
{ 
    printf("controlobject tickn"); 
    MapObject::Tick();
}

从注释复制:

恐怕这是一个糟糕的设计。代码按预期工作,它按照C++标准的定义工作。问题出在设计上。除非你提供你在更广泛的意义上试图实现的目标的细节,否则推测一个新设计是困难的,也是毫无意义的。

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

在当前示例中,您应该能够通过调用 ControlObject::Tick() 中的 MapObject::Tick() 来调用两个虚拟成员(或仅调用取决于底层类型的虚拟成员):

class ControlObject : public MapObject
{
  public:
    ControlObject()
    {
        ticks.push_front(this);
        printf("Create ControlObject %pn", this);
    }
    void Tick() { printf("controlobject tickn"); MapObject::Tick(); }
};

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