tags:

views:

164

answers:

3

I have a base class "Foo" that has an Update() function, which I want to be called once per frame for every instance of that class. Given an object instance of this class called "foo", then once per frame I will call foo->Update().

I have a class "Bar" derived from my base class, that also needs to update every frame.

I could give the derived class an Update() function, but then I would have to remember to call its base::Update() function - nothing enforces my requirement that the base::Update() function is called because I have overriden it, and could easily just forget to (or choose not to) call the base:Update function.

So as an alternative I could give the base class a protected OnUpdate() function, which could be made overrideable, and call it from the base::Update() function. This removes the onus on me to remember to call base::Update() from the derived update function because I'm no longer overriding it. A Bar instance called "bar" will have bar->Update() called on it; this will first call the base class' Update() method, which will in turn call the overriden OnUpdate() function, performing the derived class' necessary updates.

Which solves everything. Except. What if I want to derive yet another updatable class, this time from the "Bar" class.

Baz (which derives from Bar) also has update requirements. If I put them in Baz's OnUpdate() function, I'm back to the original problem in that I'd have to remember to tell Baz's OnUpdate() function to call Bar's OnUpdate() function, otherwise Bar's OnUpdate() function wouldn't get called.

So really, I'd want Bar's OnUpdate() function to be non-overridable, and instead for it to call an overridable function after it has done whatever it needed to do, perhaps called OnUpdate2()...

And if I wanted to derive yet another class? OnUpdate3? OnUpdate4? AfterUpdate?

Is there a Better Way?


Further Info:

My specific problem domain is a 3d world. I've decided my base class is a "Locator" (an object with a location and orientation).

My first derived class is a "PhysicsObject" - a Locator that also has mass, velocity, collision information, etc.

My next derived class is a "Camera" - which derives from PhysicsObject. As well as position, and velocity, it also has information about the viewport, depth of field, etc.


MattK suggests simplifying the hierarchy - if a Locator is never referred to, incorporate it into PhysicsObject.

I'm also thinking about how I would go about turning the layout upside down and using composition instead of inheritance.

Perhaps a Camera HAS physics properties. Perhaps a PhysicsObject HAS a location.

I'll have to think some more about this problem.


I like Uri's approach: "Observe the contract." Here's the rule - please follow it. Uri is right in that whatever kind of safeguards I try to put in, anyone could circumvent them, so perhaps in this case, the simplest solution is best. All my update() functions are going to have the requirement of calling their base::update() function.

Thanks for the help everyone!

+3  A: 

Sounds like you want composition instead of inheritance. What if there was an interface IUpdateable, and Foo held a collection of IUpdateable objects, and called an Update method on each one every tick? Then Bar and Baz could just implement Update; your only worry would be how best to register them with Foo.

Based on your further info: You might want to consider your main object being analagous to your PhysicsObject, and using composition to include objects that implement specific behaviors, such as those of the Camera object.

MattK
My issue with composing the physics object is that, to me, a camera has a location, and can have velocity - it feels like it IS a physics object, rather than having a physics object which HAS camera properties. Without it looking right in my head, I'd have a hard time re-writing as a composition.
Tim Gradwell
Understood. If you feel strongly about using inheritance, then another approach might be to think about where you really need separate classes. Will you ever refer directly to a Locator? If not, no need to break it out. That might at least keep your hierarchy a bit smaller and more manageable.
MattK
+2  A: 

That's a great question, I've encountered it many many times.

Unfortunately, there are at present no language mechanisms that I am familiar with for mainstream languages like C++ to do that, though I expect (at least in the future) for Java to have something with annotations.

I've used a variety of techniques including what you've suggested, each with pros and cons. Convulted approaches are not always worth the cost.

My view today is that if you really need to use inheritance (rather than composition), as it sounds here, then it is better to go for the elegant solution and observe the written contract. I admit, it's dangerous, but there are risks to the other approaches as well.

Generally speaking people are more careful reading the documentation of an overridden method than they are of a method they are using. In other words, while you would want to avoid "surprising" the user of your class, and can't count on him reading docs, you can count a little more on that in the case of inheritance, especially if you are the only user.

If you are presenting an API function and you expect many other individuals to override your subclass, you could put all kinds of sanity checks to ensure that the method was called, but in the end, you have to rely on the contract, just as so many standard library classes do.

Uri
I like the approach. Observe the contract. Here's the rule - please follow it. You're right in that whatever kind of safeguards I try to put in, anyone could circumvent them, so perhaps in this case, the simplest solution is best.
Tim Gradwell
+1  A: 

I think that what you want is not easily doable with a class hierarchy.

One possible solution is to use a library that handle signal/slots (I've use sigslot http://sigslot.sourceforge.net/).

In the base class you declare a signal.

class Base : has_slots<> {
  public:
    Base() { SignalUpdate.connect(this, &Base::OnUpdate); }
    void Update() { SignalUpdate.emit(); }
    void OnUpdate() { cout << "Base::OnUpdate" << endl; }
  private:
    signal0<> SignalUpdate;
};

Now on each "derived" class you connect such signal with you own method

class Derived : public Base {
  public:
    Derived() { SignalUpdate.connect(this, &Derived::OnDerivedUpdate); }
    void OnDerivedUpdate() { cout << "Derived::OnDerivedUpdate" << endl; }
};

(Note that this class no longer need to be a derivated from Base).

Now each time Update is called all methods that are connected will be called.

There are other framework that implement a similar behavior: boost signals, qt slots, libsigc++. You should try to take a look at these an see if they fit your needs.

Ismael