Problem Introduction
I want to serialize a Message instance to send it over the network, then receive it, and deserialize the data back into an identical Message instance, which not a problem.
The problem is that I would like others to be able to subclass the Message class, but then deserialization becomes difficult, because I don't know which subclass the serialized data is from, so I don't know which deserialization function to use.
Serialization is easier, because I can create an abstract serlialize method that subclasses would have to implement. This way, at runtime, I can just call Message::serialize().
Before the serialization occurs, all I have is a pointer to a Message instance. After the deserialization, I would like to have a pointer to the Message instance (not a pointer to a subclass of the Message class).
I have come up with a few solutions, but I don't particularly like any of them because they seem like it would be difficult to maintain. I would use them if i have to, but I'm wondering if there are other ways.
I am doing this in C++.
Problems I've run into while trying to solve bigger problem
1. Identifying which subclass the serialized data is of
I need to identify which subclass the serialized data is of in order to determine which deserialization function to use. The following are possible solutions I've thought of so far:
Serialization protocol; I can make the first byte be a character which can act as a type identifier so I can figure out which subclass it is.
This makes me wonder where I would get such a unique identifier from? Is there a way to get a unique identifier for a subclass in C++? perhapse, something similar to Java's getCanonicalName()?
2. Performing the deserialization
After determining which subclass the Message instance is of, I need to execute the deserilization function, but my immediate solutons are messy. Here are some possible solutions I've thought of so far that I would like to improve upon, and avoid otherwise:
Big switch statement; I would identify whuch subclass the message is, then switch on the subclass type, and have a case for each subclass that performs the deserialization. I would like to avoid this approach for a few reasons:
Whenever one subclasses Message, they would have to add a case to the switch statement, which would undesirable, because the existence of the switch statement is not obvious to those subclassing Message.
It can become a very large switch statement, which decreases readability.
Build a map which maps subclass IDs to deserialization functions; an entry for each subclass of the Message class would be inserted into the map, so after receiving the Message instance from the network, and determining the subclass type, I can look up the deserialization function in the map, and call it. There are issues with this solution:
I can't think of a way to force subclassers of Message to insert an entry into this map at compile time.
Thanks for reading everything.
Related
Please feel free to truncate this question if it is overly long.
I'm having some trouble understanding how to pass generic arguments to event listeners (e.g. callback functions) without breaking principles of OOP and polymorphism.
For the purposes of this question, assume the implementation is written in C++.
Let's say I have an animal class with two children, cat and dog.
I also have a doorbell event object which should cause dogs to speak(), but cats do not respond.
However, I have all of my animals stored polymorphically. I cannot simply call speak() on every animal, since cats should not respond.
One (bad) solution is to use dynamic casting to check each animal, and see if it's of type dog. If so, I call its speak function. If not, I don't. The issue here is that it breaks the purpose of polymorphism and virtual functions (not needing to know information about the children classes, but rather just the parent interface).
For a better solution, I might choose to use an event driven system. I'd have an event_manager, and each dog is registered as a listener to the doorbell event (possibly by some event ID, the event name, etc.) Perhaps each dog registers its callback function with the event.
Then, when the doorbell is rung, it tells the event_manager to invoke the callback functions of every listener registered to the doorbell event.
This is much better, but what if information about the target (the doorbell_ring) needs to be passed to the dogs? For example, how loud did it ring? If it was quiet, perhaps the dogs do not respond, based on their hearing capability. Perhaps if it is very loud, the dogs respond more aggressively.
The only solution is to pass the target doorbell into the event handler (dog) callback function.
Here is where I'm confused: every callback function must match the same function signature in order for it to be generically invokeable by the event_manager. While in this case the dogs need access to the information about the doorbell_ring, given any other event, the listener may need access to information about an entirely different target.
The only solution I can think of is passing the targets as void pointers and explicitly downcasting to the determined target type (e.g. the dogs, in this callback function, would downcast the target to the doorbell_ring* type).
While this would certainly work, isn't it essentially the same as the very first solution, wherein we check if an animal is of type dog via dynamic casting and, if so, invoke its response? Imagine that, instead of using dynamic casting, we give every animal a type identifier, and just check against each animals identifier. Now, we're simply casting an animal to a dog based on its identifier. In the event driven system, we're simply casting a target to the determined subtype based on the identifier of the event which invoked the callback.
In a round about way, doesn't this have the same design issues? We're simply using void pointer generics and downcasting to the correct type based on some type id instead of downcasting from the animal class to the dog class.
Is there a better design pattern?
I send data to and from my server.
I create a message, set the type (enum) and the objects that need to be transferred.
The message is sent as a compressed JSON string.
When I receive it I parse the message, instantiate the object and start to fill it. When I need to instantiate the data transferred I use a map that contains the name of the class as a key and a pointer to the constructor as the value.
All this works fine but now I need to consume the message and do what needs to be done with it (send an answer, write to the DB, etc).
What is the best way to do that ? For now, I check the type of the message and get each of the transferred object. But I don't know what class they are (not explicitly).
Should I dynamic cast everything (cost a lot for not much) ? Should I treat the data with the hope it will always be in the same order. Or should I store the objects as a map (with the name or a enum as the key) and cast it correctly then ?
I know that dynamic casting should not be done if possible. But here I am wondering, is it worth it to have a switch from the beginning and create the correct object and feed it the JSON ? For now the entire message is reconstructed dynamically without any problem and my message manager will handle the treatment, should I change that ?
I agree with Peter.
I'd probably use a "sniffer" function that returned an enum class JType mapping the JSON to the associated type of the message.
Then use that JType enum in a switch/case block to call the appropriate factory function which would return a std::unique_ptr.
Failure to parse would throw an exception, rather than return a unique_ptr with a nullptr.
You'd have one factory for each associated class type.
You'd have a sniffer function that would determine what type the JSON represented, returning an enum.
The happy path would be JType e = sniff(message);, and if (e == JType::Foo) std::unique_ptr<Foo_t> foo = FooFactory(message);
Throwing an exception from the factory would only occur in the exceptional case of the message and the factory disagreeing as to what should be in the message.
No list of base_class objects, but the enum class JType would have a 1:1 mapping to the classes.
Think of the JSON as being the state information "dehydrated", and the factory functions "rehydrate" the state data into new objects. The factory functions could be static class functions as part of the class, or could be freestanding functions.
Hierarchies are for polymorphism, and this isn't that situation.
I found multiple questions regarding custom QEvents. So since Qt 4 we have to derive from QEvent and register our custom type. There are some samples around.
What I want is a QWheelEvent with custom data in it. So the event should be usable everywhere as a "normal" QWheelEvent but if I want to I can check for my CustomWheelEvent type and retrieve the data from it.
The problem is that I don't know how to register the type because the constructor of the QWheelEvent does not offer the possibility to set the event type.
Looking at the internals of QEvent I could simply set the protected member Type t to an event type returned by registerEventType(). Does this have side-effects?
If I simply derive from QWheelEvent I can also use dynamic_cast to find out if it is my own event carrying my custom data. A simple static cast after a check for the type should be better though.
Any thoughts on this?
Edit: I have tried the approach with dynamic_casts but the cast seems to fail. This is possible if Qt deep-copies the event internally, so that a new QWheelEvent is created and passed through the event system instead of my CustomWheelEvent. This way my own data (defined in CustomWheelEvent) is stripped off the object and only the base class (QWheelEvent) is handled. I originally thought that the pointer is used as it is, so that I can rely on the dynamic_cast. More information on this is appreciated!
Read this:
Qt: Defining a custom event type
I think that you do want to register the event and that it will return a new unused type (number). In an example there, the static object sets the value to QEvent::None. The primary problem I see with the solution there is that it is not thread safe, so, be sure to make this thread safe somehow (like maybe call the static type method before things start so that they are initialized before it could be used in a multi-threaded way).
My question is probably just a simple question about using the c++ language, but the background/motivation involves networking code, so I'll include it
Background:
I have an application with a bunch of balls moving around according to various rules. There is a server and a client that should be as synchronized as possible about the state of each ball.
I'm using Google's Protocol Buffers to create message objects that allow the client to set up or update each ball. Balls have different states, and each ball might need to be transmitted to the client using a different message class generated by GPB. For example, one type of ball updates its position using a fixed acceleration vector, so the message corresponding to that type of ball would have position,velocity, and acceleration.
I want to store these message objects in a data structure that organizes them by position, so that clients can access only message objects that are nearby. But each message has a different class type, so I don't know how to correctly put them all in a structure.
If I were hand-writing the message classes, I would make them all be subclasses of an abstract Message base object, with an enum type member. Then I would store the messages as unique_ptrs to the abstract class and then do a static cast by the type enum whenever I needed to work with each object individually. Ideally, since I need to serialize the message objects (they each have a serializeToOutputStream(..)) function, I would make this function an abstract member of the base class and have each of the particular message classes override it, so that I could avoid a cast in some situations.
The problem is that I am not hand-writing these classes. They are generated by google's compiler. I'm sure such a situation has arisen before, so I wonder how I should deal with it in an elegant way, if there is one.
Language-Only Version of Question:
I have a fixed set of generated classes A,B,C,D... that all have a few common functions like serializeToStream(). It would be very tedious to alter these classes since their sources are generated by a compiler. I would like to store unique pointers or raw pointers to these objects in a data structure of some kind, like an std::map or std::vector, but I don't know how to do this. If possible it would be great to call some of the functions that they all have without knowing which particular class I was dealing with (such as if I call the serialize function on all of them in a vector).
There is not good way to solve your problem. Only nasty haks. For example you can store pointer to object and pointer to method of some fake type in your map. But then you must cast your classes and pointers of its methods by reinterpret to this fake type. You must remember that all who will read that your code will scold you and may be better to find the approach to create common base.
I have an Action class from which I derive several subtypes. Now, I need to associate some of these subtypes with each other, in a one-to-many relationship. The idea is that some types of Action subtype will make other subtypes available/unavailable (i.e. I also need to create them on the fly). Since in a language like C++ you cannot store type variables the only thing that makes sense is an association of string typenames.
Has anyone met a similar situation? And if so, would you simply use a non-unique associative container like std::multimap and then manually hardcode a huge switch statement for the string-type association?
Example: An action of type Attackwill eventually make Retreat available to its actor, as well as others, like Charge etc. Each action constructor takes at least one Actor reference, but it may also take other, unknown at compile-time, parameters. This last bit makes it very difficult to model this as a decision/action tree... in other words, it seems like I have to build the decision tree during runtime.