C++ class design with polymorphism - c++

I am doing some networking stuff, but the question is not related to networking. I have a generic network event handler, where I can register an network connection ("NwConnection" class) and idea is whenever a message arrives on the connection, it will call me back.
class NwEventManager {
public:
using CallBack = std::function<void(std::shared_ptr<NwConnection>)>;
registerCallback(
std::shared_ptr<NwConnection> con,
CallBack rdCallback,
CallBack errorCallBack);
};
So the application will create a NwConnection and register with Event Manager.
(NwConnection is an abstract class, which internally can be a TCP/Unix domain socket etc.)
Anyway, I need to keep some per-connection information, say some statisctics.
Currently what I am doing is:
class TcpNwConnection : public NwConnection {...}
class MyNwConnection : public TcpNwConnection {
using NwConnection::NwConnection;
....
MyStatistics& getStats ()
{
return myStats_;
}
private:
MyStatistics myStats_;
};
And in the callback, which will call me back with the NwConnection Abstract class I static cast the pointer to my type and access the stats.
// read callback
[] (std::shared_ptr<NwConnection> con)
{
auto myConn = static_cast<MyNwConnection *>(con.get());
auto& stats = myConn->getStats();
}
Is this a good approach?
Obviously the problem is, if my code has to be independant of the NwConnection type, say I want to deal with TcpConnection and UnixConnection, I cannot follow this approach (unless I do with templates).
One solution is to re-write things with connection type inside the NwConnection:
class TcpStream : public AbstractStream {}
class UnixStream : public AbstractStream {}
class NwConnection {
Message read (...)
{
return stream->read(...);
}
private:
AbstractStream *stream;
};
Now I can do my static_cast and the type of connection doesnt matter.
But what is a better way to design this thing, while allowing applications to keep the per-connection data? (I am free to rewrite any part of the code.)

Related

How can I fix and/or re-design this event class system to not require exclusively public data members?

I have an Event system in which a Manager class contains a queue of Events. The Event class is currently an abstract base class from which all specific events are derived. The idea is to allow the Manager to process() specific events that are specialized classes constructed with their own, unique parameters elsewhere in the code where the context of creation informs which event to create and how (sometimes using an Abstract Factory pattern). These Events are consumed asynchronously by Manager in a loop that continuously empties the queue, processing each event, and then destroying it as it is popped.
I designed this system to alleviate Manager from doing all of its own data manipulation. Instead, other parts of the code can queue an Event object, and that object can perform a task via its process() member, with the Manager not needing to know about it in detail.
Without an encapsulated Event system, I would be making endless additions to Manager's members: one for each task, and calling those tasks in case statements somewhere, which is terrible. I thought it would be better to use the Event system I have in the example here. This leaves Manager unchanged while various derived, specific events are defined elsewhere. This minimal example works fine, but the problem is that all derived Events need access to Manager's private data for each one's process() to have full capability as intended. If friend inheritance was allowed, simply making Event a friend class of Manager would solve the problem. Since it's not, the only way for this to work is to make all of Manager's data public (or, technically, add every new derived Event class I make as a friend to Manager).
This works, but feels wrong, and makes me think this is not the correct design. To be clear, the Manager contains a good deal of centralized information (necessary for thread sync, etc) that is more extensive than the Example would indicate. It manages network connections that will spawn a variety of different, often arbitrary events. I'd like to elegantly react to such an environment without inflating Manager with endless additional member functions every time I want to create a new type of event.
Is there a better way to achieve this code separation pattern and still retain the freedom I want for the separated code? Should I just publicize all of Manager's data after all?
The minimal Example (includes pseudocode):
class Event;
class Manager
{
public:
Manager() {}
// Event queue insertion and processing functions omitted
// private: // Commented out on purpose to allow compilation
int dataInt;
double dataReal;
std::string dataStr;
std::queue<Event *> events;
};
// Abstract Event base class with process() member
class Event
{
public:
Event(Manager * m) : manager(m)
{
process = std::bind(&Event::processKernel, this);
}
// Process the event
std::function<void(void)> process;
protected:
// Actual processing code: derived classes must define this function
virtual void processKernel() = 0;
private:
Manager * m;
};
// One example of a specialized (derived) Event
class SpecificEvent: public Event
{
public:
SpecificEvent(Manager * m, int p) : Event(m), param(p) { }
void processKernel()
{
// Intention: modify parent manager data
manager->dataInt = param;
}
private:
int param;
};
// Another specialized (derived) Event
class OtherEvent: public Event
{
public:
OtherEvent(Manager * m, double p) : Event(m), param(p) { }
void processKernel()
{
// Intention: modify parent manager data
manager->dataReal = param;
}
private:
double param;
};
// Example usage: could be inside a Manager member, or anywhere else
int main()
{
Manager manager;
// Make a SpecificEvent, pass it the manager, and its own specific parameter(s)
SpecificEvent e(&manager, 10);
//<Not shown> Add to manager's queue
// Manager processes this event at some point later with Event::process()
}
Since
If friend inheritance was allowed, simply making Event a friend class
of Manager would solve the problem
you can just get away with
struct ManagerFields { // all Manager's fields; just for the further convenience
int dataInt;
double dataReal;
};
class Manager: private ManagerFields { // only Manager and its friends know these Fields
friend class Event;
// here Manager can use dataInt, dataReal etc. just like before
};
class Event {
public:
Event(Manager* m) : manager{m} {}
virtual void process() = 0;
protected: // "friend inheritance" setup below
ManagerFields& fields() { return *manager; } // "the further convenience"
private:
Manager* manager;
};
class SpecificEvent: public Event {
public:
SpecificEvent(Manager* m, int p) : Event{m}, param{p} {}
void process() override { fields().dataInt = param; } // "friend inheritance" usage
private:
int param;
};
See the comments in the code.

c++ static observer class

I have two programs: a server and a client
class client
{
private:
Network net;
Gui gui;
};
Here's the Network class
class Network
{
public:
void receivePacket(packet)
{
Protocol::readPacket(packet)
}
};
Here's the Gui class
class Gui
{
private:
std::string informations;
public:
void displayInfo();
void updateInformation(information);
};
And here's Protocol
class Protocol
{
static void readPacket(packet)
{
if (packet.command == "refreshGui")
//I need somehow to call GUI::UpdateInformation here and give the information from packet.information
}
};
Protocol is considered as a "static class" which means that in shouldn't be instantiate. So the idea is that, when Protocol::readPacket get a packet from the server, it should be able to send the information to the GUI. However, it's not always the case, so passing a point/reference is not what I'm looking for.
It's not well illustrated but the idea is:
- Protocol::readPacket seek if we need to call GUI
- Protocol shouldn't take another argument, and shouldn't be instantiate.
Someone gave me the advice about using Observer-pattern. Protocol would be the subject and GUI the Observer. However, I couldn't make it without instantiate Protocol.
So is there a way to do it without instantiate Protocol ?
In distributed computing, it is a common pattern for the network manager of a node to receive a message and call a dispatcher associated with the message type. Your need is quite similar. Here is what you could do:
In your Network class, maintain an unordered_map< packet_type, std::function >.
When your program starts, push into that unordered_map an std::pair<"refreshGui", Gui::UpdateInformation>
In Network::receivePacket, retrieve the function from the unordered_map and call it.

How can I reduce coupling in my Event Bus implementation

In my application, I have several modules that don't fit an 'is-a' or 'has-a' relationship, but still need to communicate and pass data to each other. To try and loosely couple these modules, I've implemented an Event Bus class that handles message passing from 'event posters' to 'event listeners'.
Classes can implement IEventListener if they wish to register to receive certain events. Likewise, classes can call EventBus::postEvent() if they need to push an event out to the bus. When EventBus::update() is called EventBus processes the queue of scheduled messages and routes them to registered listeners.
EventBus.h
#pragma once
#include <queue>
#include <map>
#include <set>
#include <memory>
class IEvent
{
public:
static enum EventType
{
EV_ENEMY_DIED,
EV_ENEMY_SPAWNED,
EV_GAME_OVER
};
virtual ~IEvent() {};
virtual EventType getType() const = 0;
};
class IEventListener
{
public:
virtual void handleEvent(IEvent * const e) = 0;
};
class EventBus
{
public:
EventBus() {};
~EventBus() {};
void update();
void postEvent(std::unique_ptr<IEvent> &e);
void registerListener(IEvent::EventType t, IEventListener *l);
void removeListener(IEvent::EventType t, IEventListener *l);
private:
std::queue<std::unique_ptr<IEvent>> m_eventBus;
std::map<IEvent::EventType, std::set<IEventListener *>> m_routingTable;
};
EventBus.cpp
#include "EventBus.h"
using namespace std;
/**
* Gives the EventBus a chance to dispatch and route events
* Listener callbacks will be called from here
*/
void EventBus::update()
{
while (!m_eventBus.empty())
{
// Get the next event (e_local now owns the on-heap event object)
unique_ptr<IEvent> e_local(move(m_eventBus.front()));
m_eventBus.pop();
IEvent::EventType t = e_local->getType();
auto it = m_routingTable.find(t);
if (it != m_routingTable.end())
{
for (auto l : ((*it).second))
{
l->handleEvent(e_local.get());
}
}
}
}
/**
* Posts an event to the bus, for processing and dispatch later on
* NB: The event bus will takes ownership of the on-heap event here
*/
void EventBus::postEvent(unique_ptr<IEvent> &e)
{
// The EventBus now owns the object pointed to by e
m_eventBus.push(unique_ptr<IEvent>(move(e)));
}
/**
* Registers a listener against an event type
*/
void EventBus::registerListener(IEvent::EventType t, IEventListener *l)
{
// Add this listener entry
// If the routing table doesn't have an entry for t, std::map.operator[] will add one
// If the listener is alredy registered std::set.insert() won't do anything
m_routingTable[t].insert(l);
}
/**
* Removes a listener from the event routing table
*/
void EventBus::removeListener(IEvent::EventType t, IEventListener *l)
{
// Check if an entry for event t exists
auto keyIterator = m_routingTable.find(t);
if (keyIterator != m_routingTable.end())
{
// Remove the given listener if it exists in the set
m_routingTable[t].erase(l);
}
}
As you can see, in my current implementation, I create concrete IEvent implementations for every type of event I want to pass around. I did this so that each event can have custom data attached to it (a requirement for my situation). Unfortunately, this means my EventBus system has to know about all the users of the system, increasing the coupling between my EventBus class and the users of the class. Additionally, the IEvent interface needs to hold a list of all event types as an enum, which has the same problem (increased coupling).
Is there a way to modify this implementation so that EventBus can be totally generic (doesn't need to know about the users of the EventBus), and yet still allow me to pass custom data with each event? I looked into C++11 variadic template functions but couldn't figure out how to use them in this case.
As a side-question, am I using std::unique_ptr correctly here?
Question 1 "Is there a way to modify this implementation so that EventBus can be totally generic":
Short answer, yes.
Longer answer: There are many ways of accomplishing this. One is described here:
Both the producer and the consumer of the event needs to agree on the type/data but the EventBus itself does not need to know. One way of accomplishing this could be to use boost::signals2::signal<T> as the event type. This will give you a proven, flexible and type safe signal/slot implementation. What it will not provide, however, is the possibility to queue up slot callbacks and process them from the EventBus::update()-function.
But, that can also be remedied. By making the event type EventBus::postEvent() takes as a parameter be std::function<void()> and calling postEvent() like this:
boost::signals2::signal<int> signal;
...
eventbus.postEvent(boost::bind(signal, 42));
// note: we need to use boost::bind (not std::bind) for boost::signals to be happy
The EventBus will see a std::function<void()> and dispatch to the slot. The data (42 in this example) will be kept by the result of boost::bind and be used as the parameter when the slot is called.
Question 2 "Am I using std::unique_ptr correctly":
Almost. I would drop the reference of EventBus::postEvent making it:
void EventBus::postEvent(std::unique_ptr<IEvent> e);
By doing this, you force the caller to actively move the std::unique_ptr<IEvent> into the EventBus. This will make the user aware the EventBus takes ownership and also making it obvious to people reading the code what the intent is and how ownership is transferred.
CppCoreGuidelines R.32:
"Take a unique_ptr parameter to express that a function assumes ownership of a widget"

Design pattern for device data link

I have three types of devices (USB, COM and wireless) and one PC software to connect with them. Every device have functions like connect, read and write data from RS485 network. On PC software I must implement application layer classes to work with devices. I am looking for some design pattern to write connection between application layer and transport layer. The first idea is to write abstract class DataLink and every device will inherit from the abstract class interface (pure OOP):
class DataLink {
public:
virtual bool read() = 0;
virtual bool write() = 0;
};
class USBDevice : public DataLink {
public:
bool read() { /* some code */ }
bool write() { /* some code */ }
bool specificUSBFunction() { /* some code */ }
};
class COMDevice : public DataLink {
public:
bool read() { /* some code */ }
bool write() { /* some code */ }
bool specificCOMFunction(){ /* some code */ }
};
DataLink *dl = new COMDevice();
dl->read();
dl->write();
Now if I want to use specific USB or COM function I must use ugly cast.
The other problem is that this class must be singleton because we have only one device available so we cannot create multiple objects.
I am looking for a good way to do this using C++ (can be v11 or v14).
First, as you have an abstract class, I'd suggest you strongly to consider defining an abstract constructor.
class DataLink {
public:
virtual bool read() = 0;
virtual bool write() = 0;
virtual ~DataLink() {}
};
Now creating the devices raises some questions. Your polymorphic design would rather speak for a parameterized factory method, where a parameter (configuration data ?) would tell if a COM, USB or WIFI device is to be created:
DataLink *dl = CreateDevice("COM"); // For example. COuld use an enum as well
But you add another constraint:
This class must be singleton because we have
only one device available so we cannot create multiple objects.
In fact, the intent of a singleton is not only to ensure a single instance, but also to ensure a global point of access to it. If you don't need such a global access, I'd strongly recommend not to use a singleton here.
By the way, your constraint raises other questions: Do you have one device of each type ? Or do you have one device whatever its type is ? And most of all, won't it be possible one day, that you have to support several devices ?
So, conceptually speaking, even if you have only one device currently, the unicity is not a property of your generic device class nor its concrete implementations. It's only your current use case for creating the DataLink. I'd therefore recommend you implement a factory and derive an application specific factory to implement your creational constraints;
class DeviceFactory { // application independent
public:
enum DeviceType { COMDevice, USBDevice, ... };
DataLink *CreateDevice(std::string devicename, DeviceType t);
};
class MySpecificFactory : public DeviceFactory { // application specific constraints
std::map<std::string,DataLink*> objects;
public:
DataLink *CreateDevice(std::string devicename, DeviceType t) {
if (objects.count(devicename)!=0) {
// device already exists, either report an error, or
// return the previously created object with the same name (provided it has the same type)
...
}
else {
DataLink* dl = DeviceFactory::CreateDevice(devicename,t);
if (dl)
objects[devicename]=dl;
return dl;
}
}
};
The handling of link specific functions is orthogonal to the creation issue. The easiest and safest way is certainly the dynamic cast:
if (COMDevice* cd=dynamic_cast<COMDevice>(dl)) // nullptr if it isn't a COMDevice
cd->COMFunction();
else ...
It's difficult to advise on more specific patterns, without knowing the purpose of the link specific functions and how they relate in the context of your application.
You have a couple options, but my own personal experience is from the middle-ware approach. So that approach is what I will recommend (even if you aren't writing 'middleware' the 'ideas' can still be useful)
We had several different 'physical connections': Military Radio 1, Military Radio 2, Wifi, USB to Ethernet, etc. Each of these can be thought of as similar to your different connection types.
Make use of the Bridge Pattern which...
is meant to "decouple an abstraction from its implementation so that the two can vary independently". The bridge uses encapsulation, aggregation, and can use inheritance to separate responsibilities into different classes.
1) Define an interface that all of your connections will use.
2) Encapsulate the base atomic actions of each connection type into a 'helper' class. (open(), close(), read(), write(Byte[] data), etc.)
3) Write a bridge class that converts the universal interface to the 'helper class' implementation for each connection type.
4) Have some logic that determines which 'connection' should be 'active' at a given time, and associate the 'connection interface' with the bridge impl. of the connection type being used. (or list of connections if this is multi-cast sending, etc.)
That should do it. You have a single Interface that the 'rest' of your application can write/read from. and the "impl. details" are hidden inside your atomic action 'helper' class and/or bridge class.
Example Interface: // obviously extremely simple examle
interface IConnection{
byte[] read(int size);
void write(byte[] data);
bool open();
bool close();
}
And an implementation class:
class usb_wrapper{
// this is completely made up, but made up methods to show pattern as an example
// these methods are extreme exaggerations and not 'real' at all
int open(String connectionName, int id){
// returns connection_id of new connection
}
int close(int connection_id){...} // returns a flag if connection was closed
bool write128byte(byte[] data) {...} // you can only write 128 byte chunks
byte[] read128byte(){...} // you can only read 128 byte chunks
}
As you can see the snippets above the have 'similarities' but the actual methods have different parameters, different requirements, etc.
bridge class:
class usbConnectionBridge implements IConnection{
usb_connection conn = new usb_connection();
// Here is where you have the IConnection methods, inside these methods you
// have the logic to 'adapt' from these methods ... to the 'conn' object
byte[] read(int size){...}
void write(byte[] data){...}
bool open(){...}
bool close(){...}
// possibly additional helper methods below, etc.
}
So the 'bridge' class would wrap(encapsulate) the usb_wrapper and make it able to interact with the interface. Thereby allowing the decoupling of the interface(abstraction) from its implementation(usb_wrapper) so that the two can vary independently" which is the bridge pattern by definition.

Delegates with multiple notifications in C++

I've been considering the best way to implement delegates in C++, and so far I'm inclined to using std::function callbacks. However, some of my classes issue several delegate notifications (such as opened, closed, and changed_state). Instances interested in getting delegate notifications should assign one of its own methods (the fact that it can be private is a plus) to the event it's interested in listening to. It would be expected, however, that when some instance subscribes to any of the delegates, it would subscribe to all of them. This means that it wouldn't happen that event Foo is being issued to one instance, while event Bar is being issued to a different one. Is there a way I could enforce this condition? At no point should the callbacks be assigned to different instances (assume atomicity).
I know I could consider having a single callback with calling codes or something, but in this case that's not an option (for several reasons, one of them being that it would imply an unreasonable amount of refactoring at this point).
Note: I know that are other discussions on the topic of C++ delegates, but these usually consider a single event type, not several.
An example of what I'm considering:
class Connector
{
public:
typedef struct
{
std::function<void()> opened;
std::function<void()> closed;
std::function<void()> changed_state;
} Delegate;
Delegate delegate;
};
// Somewhere else
Connector c;
Listener l;
// This should not be manual. Ideally: c.delegate = l;
c.delegate.opened = l.handle_opened;
c.delegate.closed = l.handle_closed;
c.delegate.changed_state = l.handle_changed_state;
Add operator= for that:
class Connector
{
public:
struct Delegate
{
Delegate& operator = (const Listener& l)
{
opened = l.handle_opened;
closed = l.handle_closed;
changed_state = l.handle_changed_state;
return *this;
}
std::function<void()> opened;
std::function<void()> closed;
std::function<void()> changed_state;
};
Delegate delegate;
};
and then you can have your syntax:
c.delegate = l;