There are some good arguments for against const, here so here's my take :-
Personally, I'd not have these "OnXXXUpdated" as part of my manager classes. I think this is why there is some confusion as to best-practice. You're notifying interested parties about something, and do not know whether or not the state of the object is going to change during the notification process. It may, or may not. What is obvious to me, is that the process of notifying interested parties should be a const.
So, to solve this dilemma, this is what I would do:
Get rid of the OnXXXXUpdated functions from your manager classes.
Write a Notification Manager, here's a prototype, with the following assumptions:
"Args" is an arbitrary base-class for passing information when notifications happen
"Delegate" is some kind of a function pointer (e.g FastDelegate).
class Args
{
};
class NotificationManager
{
private:
class NotifyEntry
{
private:
std::list<Delegate> m_Delegates;
public:
NotifyEntry(){};
void raise(const Args& _args) const
{
for(std::list<Delegate>::const_iterator cit(m_Delegates.begin());
cit != m_Delegates.end();
++cit)
(*cit)(_args);
};
NotifyEntry& operator += (Delegate _delegate) {m_Delegates.push_back(_delegate); return(*this); };
}; // eo class NotifyEntry
std::map<std::string, NotifyEntry*> m_Entries;
public:
// ctor, dtor, etc....
// methods
void register(const std::string& _name); // register a notification ...
void unRegister(const std::string& _name); // unregister it ...
// Notify interested parties
void notify(const std::string& _name, const Args& _args) const
{
std::map<std::string, NotifyEntry*>::const_iterator cit = m_Entries.find(_name);
if(cit != m_Entries.end())
cit.second->raise(_args);
}; // eo notify
// Tell the manager we're interested in an event
void listenFor(const std::string& _name, Delegate _delegate)
{
std::map<std::string, NotifyEntry*>::const_iterator cit = m_Entries.find(_name);
if(cit != m_Entries.end())
(*cit.second) += _delegate;
}; // eo listenFor
}; // eo class NotifyManager
I've left some code out as you can probably tell, but you get the idea. I imagine that this Notification Manager would be a singleton. Now, ensuring that the Notification Manager is created early on, the rest of your managers simply register their notifications in their constructor like this:
MyManager::MyManager()
{
NotificationMananger.getSingleton().register("OnABCUpdated");
NotificationMananger.getSingleton().register("OnXYZUpdated");
};
AnotherManager::AnotherManager()
{
NotificationManager.getSingleton().register("TheFoxIsInTheHenHouse");
};
Now, when your manager needs to notify interested parties, it simply calls notify:
MyManager::someFunction()
{
CustomArgs args; // custom arguments derived from Args
NotificationManager::getSingleton().notify("OnABCUpdated", args);
};
Other classes can listen for this stuff.
I've realised that I've just typed out the Observer pattern, but my intention was to show that the problem is in how these things are being raised and whether they are in a const-state or not. By abstracted the process of notification out of the mananager class, recipients of the notification are free to modify that manager class. Just not the notification manager. I think this is fair.
Besides, having a single place to raise notifications is good pracice imho, as it gives you a single place where you can trace your notifications.