Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I stop using abstract base classes/interfaces and instead use boost::function/std::function?

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.

like image 668
Zeks Avatar asked Mar 07 '12 17:03

Zeks


2 Answers

Prefer well defined interfaces over callbacks

The problem with std::function (previously boost::function) is that most of the time you need to have a callback to a class method, and therefore need to bind this to the function object. However in the calling code, you have no way to know if this is still around. In fact, you have no idea that there even is a this because 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_this and 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::function is 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 of std::function is 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.

like image 178
Doug T. Avatar answered Oct 23 '22 01:10

Doug T.


I do not see how one can come to the conclusion that function pointers make abstract base classes obsolete.

A class, encapsulates methods and data that pertains to it.

A function pointer, is a function pointer. It has no notion of an encapsulating object, it merely knows about the parameters passed to it.

When we write classes, we are describing well-defined objects.

Function pointers are great for a good number of things, but changing the behaviour of an object isn't necessarily the target-audience (though I admit there may be times when you would want to do so, e.g. callbacks, as Doug.T mentions).

Please don't confuse the two.

like image 26
Moo-Juice Avatar answered Oct 22 '22 23:10

Moo-Juice