I'm building a smallish library (few kLOC) which processes stream data in C++. From the streamed data (comes in packets) the library compiles a database piece by piece and naturally has to convey that information back to the host application.
Since this is my first library I'm unsure how to proceed with the API/Interface. AFAIK I have the choice between using a CPP "Interface" or C-style callbacks. This question is not just related to the programming aspect but also to the aspect of managing the library API between versions:
Why would I use an Interface?
- Interfaces are declared once and API changes are directly reflected in that class
- It is impossible to forget a method or an event as the library just doesn't compile
- It is "cleaner" C++ than C-style Callbacks
- I'm sure what I'm doing within the library and, hide "maybe complex" stuff behind a return value
Using an Interface
class InterfaceClass {
public:
virtual bool isDataBlockComplete(...) = 0;
virtual bool isDataBaseUpdated(...) = 0;
virtual bool hasEventCompleted(...) = 0;
[..]
}
/* User code */
class SomeClass : InterfaceClass { [..] }
bool SomeClass::hasEventCompleted(...){ /* check */ }
SomeClass *instance = new SomeClass();
InterfaceClass *instance = new InterfaceClass();
if(instance->hasEventCompleted) [..]
for(i = 0; i < instance->getQueueSize(); i++ ) [..]
Why would I use C-style Callbacks?
- They can be registered and updated during runtime
- Events can be "subscribed" this way
- Helps in providing a C-Wrapper later on
- It's way faster because less code has to be written & tested by me
Using Callbacks
class InterfaceClass {
public:
registerCallback( void *f, tEvent event);
deregisterCallback(tEvent event);
}
/* User code */
void myfunc(){ .. }
instance->registerCallback(&myfunc, SOME_EVENT);
/* Gets called by the governor / observer of library */
So this is not a question of preferability, but which "style" to be used for a library. I didn't find anything on the net (it all seems to revolve around the technical aspects of using virtual abstract classes or on how to implement callbacks but no one actually discusses what I've asked above) despite a thorough search (maybe wrong choice of word combinations).
Which style is better suited for such kind of library and why? How do "professional" libraries communicate with the main applications? (Maybe too broad for SE, but trying anyway :))
2 Answers 2
I would suggest avoiding the use of C-style callbacks in C++ code. C++ provides an equivalent idiom that gives better type-safety, is easier to read (at least for most C++ developers), and may provide the compiler better chances to optimize the code. It also allows the use of lambda functions to define the behaviour at call site, which you can't achieve using function pointers. This is the std::function
template class in the <functional>
header.
Using this, your code might look like:
class InterfaceClass {
public:
registerCallback(std::function<void(MyEvent)> callback, tEvent event);
deregisterCallback(tEvent event);
};
instance->registerCallback ([] (MyEvent evt) {
/* do something here */
}, SOME_EVENT);
I suggest you to consider observer pattern. You can register and unregister event listeners (observers) at runtime.
If you want use a legacy C function as callback, you create a wrapper observer class which delegate event notifications to that callback.-
Thanks! The observer pattern was exactly what I needed. Coming from electrical engineering I never actually learned how to design good software. It's a shame, really :)Jan Krüger– Jan Krüger12/16/2016 08:59:33Commented Dec 16, 2016 at 8:59
if (instance->hasEventCompleted)
? There can be no instance that hasn't overridden the abstract method, no?