Which is better: function to override or pass a function pointer to handle events

So, I am writing code for a class that will go into a library that will be used by others. This class will intercept and process incoming messages (details are not important, but they use the activemq-cpp library). Outlines of this consumer class

class MessageConsumer { ... public: void runConsumer(); virtual void onMessage(const Message* message); } 

where runConsumer() establishes a connection and starts listening, and onMessage() is called when a message is received.

My questions are: people who will use this code will have their own way of handling various messages. How can I keep MessageConsumer generic, but offer this flexibility while keeping my code simple?

Two options:

  • Should they inherit a new class from MessageConsumer and write their own onMessage() ?
  • Should they pass a pointer to a message processing function on MessageConsumer ?

Which option do you think is better and why?

Thanks!

+4
source share
4 answers

In one approach, clients are allowed to register a callback, and then MessageConsumer calls the registered callback. This is something like an observer / translation design pattern.

The second approach, when clients need to inherit and redefine MessageConsumer, will be something like a strategy development template.

The main design goals are to use the weakest relationship to promote free grip. Since inheritance is a stronger relation than simple association, everyone else is the same. Approach 1 is preferred.

From Article on Herbs

“Inheritance is often abused, even by experienced developers. Always minimize coupling: if class relationships can be expressed in more than one of the ways, use the weakest relationships that are practical. Given this inheritance is almost the most powerful relationship that you can express in C ++ (second only for friendship), it’s really real when there’s no equivalent weakening alternative. ”

But, as James points out, it's hard to comment if the general design constraints are not known.

+6
source

Inheritance will make your library more OO friendly and improve readability. But really, the choice is about the same, since the compiler checks to see if the user has provided this function (assuming that you declare a pure virtual handler in the base class), and the main mechanism will be executed using the pointer anyway (virtual table in case of inheritance).

+1
source

Pure virtual functions allow the compiler to verify that client code implements the handler. Virtual dispatch is activated immediately after the creation of the object, and someone who looks at the derived class can accurately determine its processing. The data needed for processing can be conveniently and clearly grouped into a derived class. Factories can still select a specific derived class to instantiate.

Function pointers are a state of runtime, so you need to take care to initialize them in a timely manner, for additional checks of runtime during their installation and error handling, as well as the reason why the set is valid during program execution. In this case, there is great freedom to change them during the life of the object.

A third alternative is a Curiously Recurring Template Pattern to block compile-time behavior. This potentially allows you to embed callbacks, eliminate dead code, and other optimizations.

+1
source

virtual function or tepmlated functor is the way to go. These approaches provide more flexibility in loosening communication than the pointer function.

To illustrate that - the function pointer approach can be wrapped with the first two, but not vice versa.

 void cbFunction(); class Interface { virtual void act() =0 ; }; class CbFuctionWrapper:public Interface { public: virtual void act() {cbFunction()}; }; class AnotherImpl: public Interface { Context _c; // You can't pass additional context with usual function without downcasting, but OO is all about that. public: virtual void act() {...} } 
0
source

All Articles