I have a library, which sends and receives a set of binary messages and parses them.
So far I’ve used inheritance for my design, i.e.
class BaseMsg { // init msg from rx'd binary stream virtual bool fromBinary(std::vector<char> b) = 0; // write msg content to binary stream to tx virtual std::vector<char> toBinary() const = 0; MsgType type; }; class MsgA : public BaseMsg { MsgA() { type = MsgType::A; } bool fromBinary(std::vector<char> b) { // parse binary stream here and init members } std::vector<char> toBinary() const { // encode members to binary stream here } private: std::string freetext; // more members }; class MsgB : public BaseMsg { MsgB() { type = MsgType::B; } bool fromBinary(std::vector<char> b) { // parse binary stream here and init members } std::vector<char> toBinary() const { // encode members to binary stream here } private: double latitude; double longitude; // more members }; In addition I have a messaging class Messenger, which has methods to send and receive, i.e.
bool sendMessage(std::unique_ptr<BaseMsg> msg) { std::vector<char> bin = msg->toBinary(); // send bin } std::unique_ptr<BaseMsg> receive(std::vector<char> receivedBinaryStream) { if (/*check in binary stream, if msg is MsgA*/) { auto msg = std::make_unique<MsgA>(); msg->fromBinary(receivedBinaryStream); return std::move(msg); } if (/*check in binary stream, if msg is MsgB*/) { auto msg = std::make_unique<MsgB>(); msg->fromBinary(receivedBinaryStream); return std::move(msg); } } This works quite well, but when using the library I end up casting a lot from the base class to a specific sub class. This is especially after reception of a message and using the message in my application.
// auto msg = messenger.receive(binStream); if (msg->type == MsgType::A) { // cast to MsgA and continue processing } else if (msg->type == MsgType::B) { // cast to MsgB and continue processing } So the question is, if there's an alternative architecture/design, which would avoid the casts in the last code sample.
The question is not for details of the implementation, but if there's a better design than currently using inheritance.
edit:
Messages have different parameters, e.g. MsgA provides free text, MsgB provides location info of an object, etc.
Therefore when a message is consumed by the application, it's casted to its sub class to obtain the type specific parameters.
MsgA, but presumably soon thereafter, treat it asBaseMgs, loosing the concrete type.foobarnames, and perhaps a bit more code.BaseMsgproperly.