我有一个问题,我正在努力。我有一个数字类,它们以这种模式相互继承:
#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
函数?如果不可能/实用,什么是一个好的选择?
答案 0 :(得分:2)
您应 始终 存储指向列表中基类A*
的指针(std::list< A*>
)。
在将 指针添加到容器之前,应正确指向指针B
或C
的对象。
一旦你这样做,动态调度将负责根据实际的对象类型为你调用正确的函数。你不需要做任何事情。
我不知道为什么你想要任何其他设计,如果你有任何理由这样做,请告诉我们。
为什么它总是在您的代码中调用ControlObject::tick()
?
当你打电话:
ticks.push_front(this);
在ControlObject::ControlObject()
中你基本上最终会覆盖你添加到列表中的第一个指针,第一个推送指针的类型不再是MapObject *
它是ControlObject *
因为你改变了指针在它的后面。你没有将指针的所有权转移到列表,但你们都拥有共享所有权,你通过派生类中的构造函数调用修改了列表中的对象。这会在列表中留下两个ControlObject *
对象,动态分派正确地确定这些对象并调用正确的方法。
动态调度没有什么问题,这是正确的行为
如果你想调用MapObject::Tick();
,那么你将明确地告诉编译器这样做,动态调度对实际的对象类型起作用并且它正常工作。
void controlobject::Tick()
{
printf("controlobject tick\n");
MapObject::Tick();
}
从评论中复制:
我担心这是一个糟糕的设计。代码工作正常,它的工作原理是C ++标准。问题在于设计。除非你提供你想要实现的细节。从更广泛的意义上来说,推测新设计是困难而且毫无意义。
答案 1 :(得分:0)
对类型B使用类型C变量的强制转换应该可以解决问题。
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();
答案 2 :(得分:0)
在您当前的示例中,您应该可以通过调用MapObject::Tick()
内的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(); }
};
需要显式函数调用表示法。