I’ve just learned about what std::function really is about and what it is used for and I have a question: now that we essentially have delegates, where and when should we use Abstract Base Classes and when, instead, we should implement polymorphism via std::function objects fed to a generic class? Did ABC receive a fatal blow in C++11?
Personally my experience so far is that switching delegates is much simpler to code than creating multiple inherited classes each for particular behaviour… so I am a little confused abotu how useful Abstract Bases will be from now on.
Prefer well defined interfaces over callbacks
The problem with
std::function(previouslyboost::function) is that most of the time you need to have a callback to a class method, and therefore need to bindthisto the function object. However in the calling code, you have no way to know ifthisis still around. In fact, you have no idea that there even is athisbecause bind has molded the signature of the calling function into what the caller requires.This can naturally cause weird crashes as the callback attempts to fire into methods for classes that no longer exist.
You can, of course use
shared_from_thisand bind a shared_ptr to a callback, but then your instance may never go away. The person that has a callback to you now participates in your ownership without them even knowing about it. You probably want more predictable ownership and destruction.Another problem, even if you can get the callback to work fine, is with callbacks, the code can be too decoupled. The relationships between objects can be so difficult to ascertain that the code readability becomes decreased. Interfaces, however, provide a good compromise between an appropriate level of decoupling with a clearly specified relationship as defined be the interface’s contract. You can also more clearly specify, in this relationship, issues like who owns whom, destrcution order, etc.
An additional problem with
std::functionis that many debuggers do not support them well. In VS2008 and boost functions, you have to step through about 7 layers to get to your function. Even if all other things being equal a callback was the best choice, the sheer annoyance and time wasted accidentally stepping over the target ofstd::functionis reason enough to avoid it. Inheritance is a core feature of the language, and stepping into an overridden method of an interface is instantaneous.Lastly I’ll just add we don’t have delegates in C++. Delegates in C# are a core part of the language, just like inheritance is in C++ and C#. We have a std library feature which IMO is one layer removed from a core language functionality. So its not going to be as tightly integrated with other core features of the language. It instead helps formalize the idea of function objects that have been a C++ idiom for a good while now.