views:

333

answers:

7

I have a singleton that is the main engine container for my game.
I have several abstract classes that make the developer implement the different calls to what that specific object needs.

What I want to do is to make my singleton call those methods upon each given object, but avoiding unecessary calls.

Example so you can understand better:
Imagine one object that requires both Render() and Update() methods.

class IRender() : public IBase
{
  virtual bool Render() = 0;
};

class IUpdate() : public IBase
{
  virtual bool Update( long time_delta ) = 0;
};

class Sprite : public IRender, public IUpdate
{
  bool Render(){ render stuff; }
  bool Update( long time_delta(){ update stuff; }
};

Now I want to add that Sprite object to my singleton engine but I want the engine to call each loop to ONLY whatever that object inherited (there are other things beside Render and Update, like checking for input, etc):

_engine::getInstance()->Add( _sprite );

Thing is, for this to work I have to inherit all the interfaces from a base interface so I can call Add() with whatever objects were created, so the Add() method receives a base interface object.

Now the problem here is the base interface has to at least abstract all the methods that can be inherited like Render(), Update(), CheckInput(), Etc() and each loop my singleton has to call all the possibilities for every object, even if CheckInput() is empty for the sprite class.
Like so in my singleton:

bool loop(){
  for every object saved in my container:
    CheckInput(); Update(); Render(); etc(); }

Is my design wrong? Is there a way I can avoid this?
I hope you understand what I mean, my engine is in a pretty advanced state and I'm trying to avoid rewriting it all.

Thanks in advance.

+2  A: 

If you don't need to call the chain CheckInput(), Update(), .... on each object before moving on to the next one, make a call to to the object, and make the object register which actions it supports on the singleton.

class Singleton {
  void Add(Base& object) {
    object.register(this);
  }

  void registerForInput(IInput& object) {
    addToInputList(object);
  }
}

class Some : public Base, public IInput {
  void register(Singleton *target) {
    target->registerForInput(*this);
  }
}

However if you need to call all of them on one object before moving to the next make a method on the object which performs all the calls it supports.

class Singleton {
  void loop() {
    for all objects:
      object.performActions();
  }
}

class Some : public Base {
  void performActions() {
    checkForInput();
    render();
  }
}
Rickard
nice, didnt know about double dispatch and it solves exacly what i wanted. also my design is made so update() is called on every object, then render() etc. so it works like a charm.thanks again :)
sap
Do you really need this solution (ie performing all methods for a given object in one go) ? I have used another idea >> performing one method on all objects in one go, that is much more elegant as it does not put so much burden on the user of the Interface classes.
Matthieu M.
@Rickard - can you explain why this is considered double dispatch? It just seems like simple registration to me.
Aaron
@Aaron - you are right it's not a double dispatch. I was going for a real double dispatch first by changed it. I'll change that.
Rickard
This doesn't support multiple types on one singleton? Also, all singletons need to know about all types? Or did I miss something?
Marcus Lindblom
@Marcus - The singleton needs to know about the different types of interfaces that can be implemented and keep a list of each.
Rickard
The thing the OP needs to read up on is "The Inversion Principle". Instead of the singleton knowing details about each object, it only needs to know about what *it* needs to do - ie from the singletons perspective, it just calls 'performActions' or some better-named function. Once you know the proper name for this function, it will probably be more clear what the inversion of perspective feels like.Rickard's solution is an application of the Principle, but I just wanted to highlight the topic, as it will come in handy repeatedly. I find it to be one of the most useful idioms out there.
tony
A: 

If you have your base interface define too many pure virtual function, every derived class would have to define them. I would make single pure virtual function in IBase, lets call it EngineCommunication that in derived classes would call CheckInput(); Update(); Render() etc. (class specific) And your engine would call EngineCommunication in the loop and let concrete classes decide what to do.

BostonLogan
Read up the question again, `IBase` declare all methods `virtual` but not `pure` (probably a do nothing impl), otherwise `IRender` would not redeclare the method as pure to force the implementation.
Matthieu M.
Then IBase can not be classified as interface class (although conceptually it is). In any case - this is minor and does not affect my suggestion.
BostonLogan
+1  A: 

Pushing all the methods from the sub-classes to the base-class seems odd to say the least. Why not attempt to dynamic_cast each object to the interface with the method you want to call - if the cast returns a nullptr then skip it:

bool loop()
{
   for every object saved in my conatiner:
       IRender* render = dynamic_cast<IRender*> (object_ptr);
       if (render != 0)
           render->Render ();

       // etc.
}

Alternatively call all of the actions from a single method in the sub-class - e.g. execute(). You would probably need to use virtual inheritance for your sub-classes to have only a single IBase base.

jon hanson
Argh, a `dynamic_cast`....
Matthieu M.
would work indeed, but looks a bit ugly :p also i dont know if making a cast followed by a an if statment on every object (that can be thousands) every loop is a good ideia performance wise, but thanks for the help :)
sap
I use ´dynamic_cast´ in addObject() to check if it matches update lists (can't add it otherwise) and then avoid it in the loops.
Marcus Lindblom
I don't see the problem with the cast - semantically i read it as, "if this object is renderable then render it". Seems infinitely preferable to cluttering up the base class with the superset of all sub-class methods.
jon hanson
I agree that cluttering the base class is bad, especially because adding an interface to the collection ends up with a bigbang recompilation.... but `dynamic_cast` is usually a sign of bad design since you should never have to up-cast an object. So before relying on it blindly just because it exists, it's better to stop thinking for a second and see how to avoid it.
Matthieu M.
+1  A: 

If you want to write something like

bool loop()
{
    foreach IBase _base in _container do
    {
         _base->CheckInput();
         _base->Update();
         _base->Render();
         ...
    }
}

all your subclasses must have an implementation of each of the methods. If you don't want the final class (i.e. Sprite) to implement all the methods, you can implement that methods empty in the subclasses and then use virtual inheritance. But it will get a bit complex. Something like:

bool loop()
{
    foreach IBase _base in _container do
    {
         IChecker * _checker = dynamic_cast<IChecker *>(_base);
         if (_checker != 0)
             _checker->CheckInput();

         IUpdater * _updater = dynamic_cast<IUpdater *>(_base);
         if (_updater != 0)
             _updater->Update();

         IRender * _render = dynamic_cast<IRender *>(_base);
         if (_render != 0)
             _render->Render();
         ...
    }
}

class IBase
{
    virtual bool Render() = 0;
    virtual bool CheckInput() = 0;
    virtual bool Update() = 0;
    virtual bool Render() = 0;
    ...
}

class IRender : public virtual IBase
{
    virtual bool Render()
    {
         // do stuff
    }

    virtual bool CheckInput()
    {
        return false;
    }

    ...
}

It is complex and you repeat code for nothing. Also, I don't know exactly the performance penalty for dynamic_cast, but there must be. I hope you can use this idea to save your code.

yeyeyerman
You don't need to both have all the methods in the base class *and* use dynamic_casts - one or the other will suffice.
jon hanson
I know, this is just to avoid having to define the methods in the final classes. You can do that or defining all the empty methods in the base IBase.
yeyeyerman
+2  A: 

It sounds like early optimization to me - are you sure that you really need to avoid those calls? Typically the overhead for an empty Render() call is going to be so small compared to the work of actually pushing the pixels onto the screen that it's not worth optimizing.

However - if you really want to avoid those calls you could do something like this:

class IBase
{
  unsigned int mask;
  const unsigned int DONT_CALL_MYFUNCTION = 1;

  IBase() : mask(0) { }

  virtual void MyFunction() { mask |= DONT_CALL_MYFUNCTION; }
}


...

if((obj->mask & DONT_CALL_MYFUNCTION) == 0)
  obj->MyFunction();

You end up calling each base function once - but once the base implementation has realized that it's not overridden then it will stop calling the virtual function.

But again - I doubt it's worth the effort.

Aaron
+1  A: 

Dirty solution, to begin with :)

Just add a 'tag' to the interfaces. Obviously they are already tied together anyway, so:

class IBase { public: void addTag(Tag t); const TagLists& getTags() const; }

IRender::IRender() : IBase() { addTag(IRender::Tag); }

Then you can just ask for the 'tags' and dispatch with a switch:

const TagList& tags = base->getTags();
for(TagList::const_iterator it = tags.begin(), end = tags.end(); it != end; ++it)
{
  switch(*it)
  {
  case IRender::Tag:
    base->render();
    break;
  case IUpdate::Tag;
    base->update();
    break;
  }
}

Well, as I said, beautiful isn't it ?

The only question I have is: do you really need to do that.

Obviously it's kind of awkward... I mean with all those methods hanging around...

The only question is how you want to proceed:

  • For each object, call all the methods in a definite order
  • For each method, call it upon all the objects

Object centric

I don't have any idea how to do it properly: the go method that summarizes them all would end up with a LOT of parameters :/

Then you would need masks, or registrations...

Method centric

One singleton to contain the objects (if it's that necessary), one singleton RenderSingleton which holds a pointer to each object derived from Render.

class Render
{
public:
  Render() : Base() { RenderSingleton::Add(this); }
  ~Render() { RenderSingleton::Remove(this); }
};

class RenderSingleton
{
public:
  static void Add(Render* i);
  static void Remove(Render* i);

  static void Render(....); // calls on each obj with specific render parameters
};

The main advantage here is that the parameters are specific to the render method, no need to pass parameters for check etc... which promotes decoupling.

Also, note that if you add a new interface, it's independent of the others.

Go for this if you can.

Matthieu M.
argh, a switch statement on an object type...
jon hanson
which is why it's presented as dirty, by the way :)
Matthieu M.
+1  A: 

What I usually do is define a listener object with a templated subclass that does dynamic_cast and passes it on to the "updater", this is then called when object's of the right type are added/removed.

class ObjectListenerBase 
{
private:
    friend class ObjectManager;

    void onAdded(ScriptObject* obj) { doOnAddedBase(obj); }
    void onRemoved(ScriptObject* obj) { doOnRemovedBase(obj); }

    virtual void doOnAddedBase(ScriptObject* obj) = 0;
    virtual void doOnRemovedBase(ScriptObject* obj) = 0;
};

template<class T>
class ObjectListener : public ObjectListenerBase
{
protected:
    virtual void doOnAdded(T* obj) = 0;
    virtual void doOnRemoved(T* obj) = 0;

private:
    void doOnAddedBase(ScriptObject* obj) { if (T* o = dynamic_cast<T*>(obj)) { doOnAdded(o); } }
    void doOnRemovedBase(ScriptObject* obj) { if (T* o = dynamic_cast<T*>(obj)) { doOnRemoved(o); } }
};

//// how add object might look like

void ObjectManager::addObject(const std::string& object_name, ScriptObjectPtr s_object)
{
    ....

    for_each(m_listeners, boost::bind(&ObjectListenerBase::onAdded, _1, s_object.get()));
}

//// how a listener might look like
class AIEngine : public ObjectListener<IThinker>
{
public:
    AIEngine() { ObjectManager::the().addListener(this); }

    void think() { for_each(m_ais, boost::bind(&IThinker::think, _1, ...));

protected:
    virtual void doOnAdded(IThinker* obj) { m_ais.push_back(obj) }
    virtual void doOnRemoved(IThinker* obj) { m_ais.erase(obj); }

private:
    ptr_set<IThinker> m_ais;
}

You can inherit ObjectListener several times for different types if you'd like.

Marcus Lindblom
Interesting use of `dynamic_cast`, once means there isn't much performance penalty. But using templates, you could avoid it altogether.
Matthieu M.
How would I avoid it altogether by using templates? (Note, I wish to separate stuff into h/cpp so that I don't have to #include everything with everything else.)
Marcus Lindblom