Basically, you are doing data serialization and unserialization when you do this sort of thing. Since you are doing C+, you can pretty easily write a serialization base class that you then derive from for your
classes that need serialization (virtual keyword). Then you pass the base class to Packet - it calls the virtual function in the base class that ends up calling your implementation.
I also recommend, if possible, using JSON for cross-platform sanity purposes (e.g. sending a float value). The only reasons to not use JSON are extensive binary data transfers and tons of small data objects. If you have to do either of those, then a binary serialization data format might be better. JSON parsers and generators exist for C and C+ (e.g. wxJSON if you use wxWidgets). Parsing tons of JSON might not be efficient either though - performance could suffer depending on what it is being used for. Pauls recommendation of the Google protocol buffers might be better.
One other tip: Make sure your system allows you to stream packets of data. Doing the whole "send data packet, receive data packet, send next packet, receive next packet..." thing is really old-school. You should
be able to send 10 packets and receive responses to those packets whenever because that plays nicer with TCP/IP. Use an incremental counter to track the packet number so you can match the response to the original message and get it to the right destination. If you dont care about performance and will always deliver packet responses in the same order they were sent in, the back and forth thing works fine enough.