0

I have a user-defined class, say, MyClass. Suppose its definition is as follows:

class MyClass
{
    int a;
    int *b;
    Base *c;
};

where I have

class Base
{
    int base_data;
    public:
        Base(int) { //implementation }
        virtual void some_func() = 0;
}

and

class Derived1 : public Base
{
    int derived_1;
    public:
        Derived1(int) { //implementation }
        virtual void some_func() { //implementation }
}

and

class Derived2 : public Base
{
    int derived_2;
    public:
        Derived2(int) { //implementation }
        virtual void some_func() { //implementation }
}

I would like to send an object of this class to a QTcpsocket. As per this answer, I could use a QDataStream, and with the help of this, I have implemented as follows:

friend QDataStream& operator<<(QDataStream&, const MyClass&);
friend QDataStream& operator>>(QDataStream&, MyClass&);

in the class declaration, and am considering defining it as:

QDataStream& operator<<(QDataStream &stream, const MyClass &obj)
{
    stream << obj.a;
    stream << obj.(*b);
    stream << obj.(*Base); // assume QDataStream has been overloaded for Base already
}

As I need to send the data, I am dereferencing the pointers and sending the data it points to.

Is this the correct way to do this?

If I do send it this way, I am not able to understand how I can recreate the object at the receiving end. I am considering:

QDataStream& operator<<(QDataStream &stream, MyClass &obj)
{
    stream >> obj.a;
    b = new int;
    stream >> obj.(*b);
    Base = new //what?
    stream >> obj.(*Base); // assume QDataStream has been overloaded for Base already
}

For an int pointer, I can create a new int and assign the incoming value to it. But what about a pointer of type Base? I don't know if it is of type Derived1 or Derived2.

How do I handle this?

Is there any other way to send a class object, if there is no solution here?

Thank you.

Community
  • 1
  • 1
GoodDeeds
  • 7,956
  • 5
  • 34
  • 61
  • 2
    **All of the questions you are posing should be decided by you.** In most cases, It is meaningless to send a memory address over the `QTcpSocket` (unless the receiver and the sender live in the same process, in which case there are far more effective ways to communicate other than using network sockets). As a general rule, You just need to send data that is enough to recreate the class at the receiver side. – Mike Feb 27 '17 at 13:39
  • @Mike I did not mean to send a memory address. My query is, how will I know the type of the data pointed to by `Base`, as it can be any of its derived classes? As a result, how do I even create an object to receive the data from the stream? – GoodDeeds Feb 27 '17 at 13:41
  • Are the writer and reader of the stream in the same process? What if the pointed-to object ceases to exist before the receiving code tries to use it? – Peter Feb 27 '17 at 13:42
  • 3
    As I said, **You should be sending enough data to be able to recreate the class at the receiver side.** As far as I can see, you are not doing so right now (as you are not able to tell if the original object contained a `Derived1`/`Derived2`). As a solution, you can send an extra `quint16` that you set to `1` when you should create a `Derived1` and set it to `2` when you should create `Derived2`. In the receiving side, You can decide what type you need by looking at this extra `quint16`. – Mike Feb 27 '17 at 13:45
  • 2
    "how will I know the type of the data pointed to by `Base`[...]?" First, think of how you would tell a fellow programmer. Then realize that a data stream is just a means of communicating stuff. You have to establish some language, some protocol that you will use that both sides of the conversation understand. You could use plain English for all I know. It's entirely up to you how you will do it. You know the application. – Kuba hasn't forgotten Monica Feb 27 '17 at 13:46
  • @Peter It seems there is a big gap in my understanding here. Is a _reference_ passed in a QDataStream, instead of a copy of the value? I thought that if I send, say, and `int` variable, the value will be sent, not a reference to it. After all, it might be sent to a completely different system via a `QTcpsocket`, so I don't get how it can be a reference. If it is indeed by value, doesn't dereferencing the pointer before sending make it send the value, and not an address? – GoodDeeds Feb 27 '17 at 13:47
  • @Mike That seems a very nice and simple solution. Thank you! Somehow I hadn't thought of this at all. – GoodDeeds Feb 27 '17 at 13:48
  • @KubaOber Thank you. I had not thought of establishing my own protocol, though this seems a very intuitive idea. Thank you for the solution. – GoodDeeds Feb 27 '17 at 13:51
  • "Is a reference passed in a QDataStream" You're mixing up the API of the class, and its behavior. I can have some ice cream on the table, and I can call you and describe it over the phone. I haven't eaten nor copied the ice cream to do it, only referenced it. The data stream API does the same thing, as would any other C++ API: it will take large objects by a const reference, and small objects of the size of `void*` and smaller by value, since those values are cheap to copy usually. In your own code, if you see methods that take a `QFoo` class by value, consider `const QFoo &` instead. – Kuba hasn't forgotten Monica Feb 27 '17 at 14:21
  • @KubaOber Okay, so what you mean is that a `QDataStream` takes a reference of the object. But when the data is written to a `QByteArray` and sent, it cannot be the "reference" right, as there is no longer any notion of a data type? So why does the receiver have to worry whether the sender's pointer points to something else after it receives it? (This is what I understood from Peter's comment, please correct me if I am wrong). – GoodDeeds Feb 27 '17 at 14:34
  • 1
    The receiver never receives any pointers. I mean, yes, you can send pointers around, but in most cases it'd be pointless unless the sender and receiver share memory so that the pointer can be used for something. The stream takes reference to an object and then uses that to access the object to read its data and compose it as a stream of bytes. Const references are how you access read-only values in C++. E.g. `void print(const std::string &)`. – Kuba hasn't forgotten Monica Feb 27 '17 at 15:03
  • 1
    Apart of all the serialisation topic, be aware when deserialising objects that involve pointers: you may create a memory leak on `b = new int;` and similar. You can use an `std::unique_ptr` or a setter method. – cbuchart Feb 27 '17 at 23:01

0 Answers0