假设我有一个名为Country的类和两个名为AI和Player的子类。国家级有许多虚拟方法来允许特定玩家或特定于AI的行为.
我想让玩家在一场比赛中转换国家成为可能。为此,我正在重构与组合的继承关系。然后,我将能够切换一个球员的国家的内部实例在任何时候的另一个。
但这带来了一个问题:当外部对象试图调用播放机上的这些虚拟方法之一时,在完成任何适当的处理之后,将正确地委托给Country方法。但是,当内部Country方法调用其中一个虚拟方法时,播放器或AI版本中的代码就不再有机会运行了。
因此,现在我需要更新这些方法中的每一个,以确保两个版本都被调用,这本身并不是一个简单的任务(无限循环,有人吗?)
这似乎比该做的要困难得多。我以前做过类似的重构,从来没有遇到过这个问题。为什么?我是不是漏掉了一些显而易见的观察结果?
既然我再次访问了代码,请编辑一个具体的示例:
class Country
{
public:
virtual void AddMoney(float money)
{
_vMoney += money;
}
void TakeLoan()
{
float loan = ...;
AddMoney(loan); // <-- does not route through AI or Player implementation
}
}class AI // : public Country
{
private:
Country *pCountry;
public:
virtual void AddMoney(float x)
{
pCountry->AddMoney(x); // formerly Country::AddMoney(x)
AllocateMoney(x);
}
}发布于 2011-06-06 17:52:02
所以让我们把这个做成混凝土吧。
class Country {
virtual void foo();
void bar() {
foo();
}
}向以下方向移动:
class Country {
private thingWhichWasSubclass;
void bar() {
thingWhichWasSubclass.foo();
}
}是那么回事吗?作为中间的一步怎么样:
class Country {
private thingWhichWasSubclass;
void foo() {
thingWhichWasSubclass.foo();
}
void bar() {
foo();
}
}?
这能行吗?然后(当然)内联Country.foo()。
发布于 2015-05-08 09:09:46
我也有同样的问题,但这次是用Java。我找到了一种在java中使用非静态嵌套类的解决方案--在C++中它可以转换成如下所示:
class AI // : public Country
{
private:
Country *pCountry;
public:
class Super : public Country {
AI* outerThis;
public:
Super(AI* outer, ...)
{
outerThis = outer;
}
virtual void AddMoney(float x)
{
Country::AddMoney(x);
outerThis->AllocateMoney(x);
}
}
// Just delegating calls to pCountry...
virtual void AddMoney(float x)
{
pCountry->AddMoney(x);
}
}当然,您需要实例化AI::Super以便获得与特定AI对象相关联的国家。也许可以从AI对象本身实例化它(这就消除了AI:Super的需要)。
基本上,用构图代替继承就是在场景后面做些什么。在场景后面,它的组合加上对虚拟函数调度表的扩展。在没有虚拟函数的情况下,这是直接的,但在虚拟函数的情况下,您将不得不考虑这些因素。通常这样做的方法(幕后)是让由基类的条目(用overriden函数替换)组成的虚拟表,然后是派生类的条目,但它也可以通过为基对象(重写的函数替换)和派生类中的新的虚拟方法的vtable(如我的例子)实现。在后一种情况下,可以单独分配基本对象,并只存储指向它的指针。
唯一的循环引用她是AI <-> AI::Super,这可能导致循环调用。然而,从AI到AI::Super的唯一调用应该是包装来自基类的方法,而来自AI::Super的调用类似于派生类中的调用方法,不应该出现无限递归。
https://softwareengineering.stackexchange.com/questions/81976
复制相似问题