Qt — QDataStream с перегруженным оператором‹‹ для указателя объекта (класс*)

Я пытаюсь читать/писать свои пользовательские классы, используя QDataStream. Я переопределил операторы ‹‹ и >>, которые отлично работают для обычных объектов. Однако, когда я пытаюсь передать указатель на свой пользовательский объект, переопределенные операторы не работают должным образом.

Вот соответствующие данные из card.h:

#ifndef CARD_H
#define CARD_H

#include <QDataStream>
#include <QImage>
#include <QString>

class Card
{
private:
    QString name;
    QImage image;
    QString type;

    int strength;
    int movement;
    int deployCost;

    QString back;

public:
    Card();

    QDataStream& read(QDataStream &dataStream);
    QDataStream& write(QDataStream &dataStream) const;

    ...
};

QDataStream& operator <<(QDataStream &out, const Card &c);
QDataStream& operator >>(QDataStream &in, Card &c);
QDataStream& operator <<(QDataStream &out, const Card *c);
QDataStream& operator >>(QDataStream &in, Card *c);
//QDataStream& operator <<(QDataStream &out, const Card *&c);
//QDataStream& operator >>(QDataStream &in, Card *&c);

#endif // CARD_H

А вот и card.cpp:

#include "card.h"

Card::Card()
{
}

QDataStream& operator <<(QDataStream &out, const Card &c) {
    return c.write(out);
}

QDataStream& operator >>(QDataStream &in, Card &c) {
    return c.read(in);
}

QDataStream& operator <<(QDataStream &out, const Card *c) {
    return c->write(out);
}

QDataStream& operator >>(QDataStream &in, Card *c) {
    return c->read(in);
}

/*QDataStream& operator <<(QDataStream &out, const Card *&c) {
    return c->write(out);
}

QDataStream& operator >>(QDataStream &in, Card *&c) {
    return c->read(in);
}*/

QDataStream& Card::read(QDataStream &dataStream) {
    dataStream >> name;
    dataStream >> image;
    dataStream >> type;

    dataStream >> strength;
    dataStream >> movement;
    dataStream >> deployCost;

    dataStream >> back;
    return dataStream;
}

QDataStream& Card::write(QDataStream &dataStream) const {
    dataStream << name;
    dataStream << image;
    dataStream << type;

    dataStream << strength;
    dataStream << movement;
    dataStream << deployCost;

    dataStream << back;
    return dataStream;
}

...

Как видите, я пробовал оба

QDataStream& operator <<(QDataStream &out, const Card *c);
QDataStream& operator >>(QDataStream &in, Card *c);

и

//QDataStream& operator <<(QDataStream &out, const Card *&c);
//QDataStream& operator >>(QDataStream &in, Card *&c);

Если я использую «Card *c», данные записываются нормально, но при попытке чтения я получаю SEGFAULT. Если я использую «Карта *&c», программа даже не распознает, что я переопределил оператор, поэтому она не вызывается.

Что я делаю неправильно?

ИЗМЕНИТЬ:

Проблема возникает, когда я читаю или пишу «карты», которые представляют собой QHash, определенный в файле deck.h как

QHash<QString, Card*> cards;

колода.ч:

#ifndef DECK_H
#define DECK_H

#include <QDataStream>
#include <QHash>

#include "card.h"

class Deck
{
private:
    QString name;
    QHash<QString, Card*> cards;

public:
    Deck();

    QDataStream &read(QDataStream &dataStream);
    QDataStream &write(QDataStream &dataStream) const;

    ...
};

QDataStream &operator<<(QDataStream &out, const Deck &d);
QDataStream &operator>>(QDataStream &in, Deck &d);

#endif // DECK_H

колода.cpp:

#include "deck.h"

Deck::Deck()
{
}

QDataStream &operator<<(QDataStream &out, const Deck &d) {
    return d.write(out);
}

QDataStream &operator>>(QDataStream &in, Deck &d) {
    return d.read(in);
}

QDataStream &Deck::read(QDataStream &dataStream) {
    dataStream >> name;
    // Reading the QHash - one problem spot
    dataStream >> cards;
    return dataStream;
}

QDataStream &Deck::write(QDataStream &dataStream) const {
    dataStream << name;
    // Writing the QHash - the other problem spot
    dataStream << cards;
    return dataStream;
}

...

Поскольку карты хранятся как указатели в QHash, я не уверен, как мне обойти переопределение оператора указателя. Есть ли лучший способ чтения/записи QHash или *Card, хранящейся в QHash?

ИЗМЕНИТЬ:

Согласно ответу Марека Р., я искал способ избежать написания карты *. Решение заключалось в повторении QHash и сохранении каждой отдельной карты.


person Elessar    schedule 16.05.2014    source источник
comment
Если вы пробовали Card *&c, почему они до сих пор комментируются? Если у вас есть проблемы с этой частью кода, не комментируйте их в своем посте.   -  person Tay2510    schedule 16.05.2014
comment
Я поместил это туда, чтобы продемонстрировать, что я пробовал оба способа. Однако программа не будет компилироваться с обоими, так как это создает двусмысленность, поэтому я закомментировал один из них.   -  person Elessar    schedule 17.05.2014


Ответы (2)


Первая проблема заключается в том, что вы пытаетесь сделать этот оператор для указателя. Если бы мой коллега поступил так, я бы, наверное, попытался его задушить. В 99,9999% случаев никогда не перегружайте операторы для указателей.

Если вы настаиваете на этом, я предполагаю, что ваш код с использованием этого оператора выглядит так:

Card *uninitializedPointer;
someDataStream >> uninitializedPointer; // SEGFAULT

И это неправильно, так как uninitializedPointer это .. его имя говорит, в чем проблема, вы имеете в виду ограниченный или случайный кусок памяти.
Возможно, вы хотите (это неправильно, но это сработает, я показываю только это объяснить сбой не как исправление):

Card *initializedPointer = new Card;
someDataStream >> initializedPointer;

Or:

Card object;
someDataStream >> &object;

Не пытайтесь исправить это, выполнив выделение в операторе, или вы будете жариться в аду :) Просто выбросьте операторы, перегруженные для указателей, которые вам действительно не нужны.

person Marek R    schedule 16.05.2014
comment
Я бы хотел избавиться от оператора для указателя. Добавил информацию о вызове оператора для QHash<QString, Card *>. Как я могу это исправить? - person Elessar; 17.05.2014
comment
Я только что понял, что могу избежать карты *, перебирая QHash и сохраняя каждую карту. Спасибо за помощь! - person Elessar; 17.05.2014

Ожидаемые подписи для операторов потока:

stream& operator<<(stream& out, const T& t);
stream& operator>>(stream& in, T& t);

См. Как правильно перегрузить оператор ‹‹ для ostream? или оператор QDatastream›› для QList‹Class*›, например.

Это относится и к QDataStream. Сложность здесь заключается в том, что T — это тип указателя, но по сути вы просто заменяете T своим типом указателя. Итак, ваши подписи должны быть:

QDataStream& operator<<(QDataStream &out, Card* const& c);
QDataStream& operator>>(QDataStream &in, Card*& c);

Обратите внимание на размещение const в Card* const, потому что константой должен быть указатель, а не указатель.

person nyibbang    schedule 19.04.2016