C++ – Is it possible to refactor inheritance to composition when virtual methods are called inside the base class

ccompositioninheritancerefactoring

Let's say I have a class called Country and two subclasses called AI and Player. The Country class has a number of virtual methods to allow player-specific or AI-specific behavior.

I want to make it possible for the player to switch countries during a game. To this end, I am refactoring the inheritance relation to composition. Then I will be able to switch out a Player's internal instance of Country for another at any time.

But this brings up a bit of a problem: When an external object attempts to call one of these virtual methods on a Player, it is delegated correctly to the Country method after any appropriate processing has been done. But when an internal Country method calls one of the virtual methods, the code in the Player or AI version no longer has a chance to run.

So now I'm left with updating every one of those methods to make sure both versions are called, which in itself is not a trivial task (infinite loops, anyone?).

This seems much harder than it ought to be. I've done similar refactorings before and never run into this issue. Why? Am I missing some blindingly obvious observation?


Edit for a concrete example now that I have access to the code again:

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

Best Answer

So let's make this concrete-ish.

class Country {
  virtual void foo();
  void bar() {
    foo();
  }
}

Moving toward:

class Country {
  private thingWhichWasSubclass;
  void bar() {
    thingWhichWasSubclass.foo();
  }
}

Is that right? How about as an intermediate step:

class Country {
  private thingWhichWasSubclass;
  void foo() {
    thingWhichWasSubclass.foo();
  }
  void bar() {
    foo();
  }
}

?

Would that do it? Then (of course) inline Country.foo().