Qt - QDataStream with overloaded operator<< for object pointer (Class*) - c++

I am trying to read/write my custom classes using QDataStream. I have overridden the << and >> operators, which seem to work fine for normal objects. However, when I try to pass a pointer to my custom object, the overridden operators don't work properly.
Here is the relevant data from 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
And here is 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;
}
...
As you can see, I've tried both
QDataStream& operator <<(QDataStream &out, const Card *c);
QDataStream& operator >>(QDataStream &in, Card *c);
and
//QDataStream& operator <<(QDataStream &out, const Card *&c);
//QDataStream& operator >>(QDataStream &in, Card *&c);
If I use "Card *c", the data writes fine, but I get a SEGFAULT when I try to read. If I use "Card *&c", the program doesn't even recognize that I've overridden the operator, so it doesn't get called.
What am I doing wrong?
EDIT:
The problem comes when I am reading or writing "cards" which is a QHash defined in deck.h as
QHash<QString, Card*> cards;
deck.h:
#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
deck.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;
}
...
Because the cards are stored as pointers in the QHash, I'm not sure how I am supposed to get around overriding the pointer operator. Is there a better way to read/write the QHash, or the *Card stored in the QHash?
EDIT:
As per Marek R's answer, I looked for a way to avoid writing a Card*. The solution was to iterate through the QHash and save each individual Card.

First problem is that you are trying to do this operator for pointer.
If my coworker would do this I would probably try to strangle him. For 99.9999% of cases never overload operators for pointers.
If you insist on doing that I guessing that you code with usage of this operator looks like this:
Card *uninitializedPointer;
someDataStream >> uninitializedPointer; // SEGFAULT
And this is wrong since uninitializedPointer is .. its name says what is the problem, you are referring to restricted or random chunk of memory.
Probably you want (this is wrong to but it will work, I'm showing this only to explain crash not as a fix):
Card *initializedPointer = new Card;
someDataStream >> initializedPointer;
Or:
Card object;
someDataStream >> &object;
Do not try fix this by do allocation in operator or you will fry in hell :)
Simply trash operators overloaded for pointers you really don't need them.

The expected signatures for stream operators are:
stream& operator<<(stream& out, const T& t);
stream& operator>>(stream& in, T& t);
See How to properly overload the << operator for an ostream? or QDatastream operator>> for QList<Class*> for instance.
This applies to QDataStream as well. The difficulty here comes the fact that T is a pointer type, but essentially you just replace T by your pointer type. So your signatures should be :
QDataStream& operator<<(QDataStream &out, Card* const& c);
QDataStream& operator>>(QDataStream &in, Card*& c);
Note the placement of const in Card* const, because it is the pointer that needs to be const, not the pointee.

Related

How does cin read strings into an object of string class?

Reading some documentation online I found that istream class was part of C++ long before the string class was added. So the istream design recognizes basic C++ types such as double and int, but it is ignorant of the string type. Therefore, there are istream class methods for processing double and int and other basic types, but there are no istream class methods for processing string objects.
My question is if there are no istream class methods for processing string objects, why this program works and how ?
#include <iostream>
int main(void)
{
std::string str;
std::cin >> str;
std::cout << str << std::endl;
return 0;
}
This is possible with the use operator overloading. As shown in the below example, you can create your own class and overload operator>> and operator<<.
#include <iostream>
class Number
{
//overload operator<< so that we can use std::cout<<
friend std::ostream& operator<<(std::ostream &os, const Number& num);
//overload operator>> so that we can use std::cin>>
friend std::istream &operator>>(std::istream &is, Number &obj);
int m_value = 0;
public:
Number(int value = 0);
};
Number::Number(int value): m_value(value)
{
}
std::ostream& operator<<(std::ostream &os, const Number& num)
{
os << num.m_value;
return os;
}
std::istream &operator>>(std::istream &is, Number &obj)
{
is >> obj.m_value;
if (is) // check that the inputs succeeded
{
;//do something
}
else
{
obj = Number(); // input failed: give the object the default state
}
return is;
}
int main()
{
Number a{ 10 };
std::cout << a << std::endl; //this will print 10
std::cin >> a; //this will take input from user
std::cout << a << std::endl; //this will print whatever number (m_value) the user entered above
return 0;
}
By overloading operator>> and operator<<, this allows us to write std::cin >> a and std::cout << a in the above program.
Similar to the Number class shown above, the std::string class also makes use of operator overloading. In particular, std::string overloads operator>> and operator<<, allowing us to write std::cin >> str and std::cout << str, as you did in your example.
Because std::string overload the >> and << operator to return the type std::istream and std::ostream
How they overload it, you can look in this link that Mat gives.
You can create your own class and overload operators, too. Here is an example:
class MyClass
{
int numberOne;
double numberTwo;
public:
friend std::ostream& operator<<(std::ostream &out, const MyClass& myClass);
friend std::istream& operator>> (std::istream& in, MyClass& myClass);
};
// Since operator<< is a friend of the MyClass class, we can access MyClass's members directly.
std::ostream& operator<<(std::ostream &out, const MyClass& myClass)
{
out << myClass.numberOne << ' ' << myClass.numberTwo;
return os;
}
// Since operator>> is a friend of the MyClass class, we can access MyClass's members directly.
std::istream& operator>> (std::istream& in, MyClass& myClass)
{
in >> myClass.numberOne;
in >> myClass.numberTwo;
return in;
}
int main()
{
MyClass myClass;
std::cin >> myClass;
std::cout << myClass;
}
Because of operator overloading.
In your case, including <iostream> will include <string>, a specialization of std::basic_string. And std::basic_string has the non-member functions operator<< and operator>> defined.
Similarly, you can also overload operator<< and operator>> for your own custom types.

Cannot access friend classes private variable in overloading "<<" and ">>" (Using multiple files)

I was just learning about friend classes and overloading operators in C++ where I came upon an issue where I cannot access the private variables in the friend class. I'm almost sure this has to do with the fact we were required to have each file separate (Header, .cpp and main). Need some fresh eyes.
// Contents of Percent.h
#ifndef PERCENT_H
#define PERCENT_H
#pragma once
class Percent
{
// friend const Percent operator >>(Percent& first, Percent& second);
public:
friend bool operator ==(const Percent& first,
const Percent& second);
friend bool operator <(const Percent& first,
const Percent& second);
Percent();
friend istream& operator >>(istream& inputStream,
Percent& aPercent);
friend ostream& operator <<(ostream& outputStream,
const Percent& aPercent);
//There will be other members and friends.
private:
int value;
};
// Contents of Percent.cpp
#include <iostream>
#include "Percent.h"
using namespace std;
istream& operator >>(istream& inputStream,
Percent& aPercent)
{
char percentSign;
ERROR HERE - Cannot access value
inputStream >> aPercent.value;
inputStream >> percentSign;
return inputStream;
}
ostream& operator <<(ostream& outputStream,
const Percent& aPercent)
{
outputStream << aPercent.value << '%';
return outputStream;
}
#endif // !PERCENT_H
// Main.cpp
not written yet

Using QDataStream to serialize custom class causes C2679 error

I'm writing an application in which I need serialization to store some data in files. For serialization I want to use the QDataStream class.
I can't compile my code due to this compiler error:
Error 1 error C2679: binary '<<' : no operator found which takes a
right-hand operand of type 'const CListItem' (or there is no
acceptable conversion) c:\qt\4.8.6\src\corelib\io\qdatastream.h 265
See the relevant code below. Anyone knows what's going on here?
There is a similar question which didn't help me. When I follow the steps described there, I get this (similar) error:
Error 1 error C2678: binary '<<' : no operator found which takes a
left-hand operand of type 'QDataStream' (or there is no acceptable
conversion) c:\qt\4.8.6\src\corelib\io\qdatastream.h 265
This is my problem:
What I want to serialize is a class called CMPProject.
CMPProject holds
CListModel* m_pData;
QDateTime m_dateTimeCreated;
This is basically what should be serialized.
CMPProject has operators to stream its contents into a QDataStream.
MPProject.h:
#ifndef _MPPROJECT_
#define _MPPROJECT_
#include <QtCore/QString>
#include <QtCore/QFile>
#include <QtCore/QDateTime>
#include "ListModel.h"
class CMPProject
{
public:
// ...
friend QDataStream& operator <<(QDataStream& stream, const CMPProject& project);
friend QDataStream& operator >>(QDataStream& stream, CMPProject& project);
private:
static const quint32 m_streamHeader = 0x1329453;
QFile* m_pFile;
CListModel* m_pData;
QDateTime m_dateTimeCreated;
};
#endif // _MPPROJECT_
The data stream operators in MPProject.cpp:
QDataStream& operator <<(QDataStream& stream, const CMPProject& project)
{
return stream << project.m_dateTimeCreated << *(project.m_pData);
}
QDataStream& operator >>(QDataStream& stream, CMPProject& project)
{
return stream >> project.m_dateTimeCreated >> *(project.m_pData);
}
m_pData is of type CListModel. CListModel contains the actual data stored as a QList<CListItem>.
To serialize the CListModel I added the according operators in ListModel.h:
#ifndef _LISTMODEL_
#define _LISTMODEL_
#include <QtCore/QAbstractListModel>
#include <QtCore/QList>
#include <QtCore/QStringList>
#include "ListItem.h"
typedef QMap<unsigned int, QString> TValueMap;
class CListModel : public QAbstractListModel
{
public:
// ...
template<typename T>
friend void operator <<(QVariant& data, const QList<T>& target);
template<typename T>
friend void operator >>(const QVariant& data, QList<T>& target);
friend QDataStream& operator <<(QDataStream& stream, const CListModel& listModel);
friend QDataStream& operator >>(QDataStream& stream, CListModel& listModel);
private:
QList<CListItem> m_items;
};
#endif // !_LISTMODEL_
and ListModel.cpp:
template<typename T>
void operator <<(QVariant& data, const QList<T>& target)
{
QVariantList list;
list.reserve(target.count());
for (int i = 0; i < target.count(); i++) {
QVariant item;
item << target[i];
list.append(item);
}
data = list;
}
template<typename T>
void operator >>(const QVariant& data, QList<T>& target)
{
QVariantList list = data.toList();
target.reserve(list.count());
for (int i = 0; i < list.count(); i++) {
T item;
list[i] >> item;
target.append(item);
}
}
QDataStream& operator <<(QDataStream& stream, const CListModel& listModel)
{
// ERROR C2679 does not occur when I change this line to "return stream;"
return stream << listModel.m_items;
}
QDataStream& operator >>(QDataStream& stream, CListModel& listModel)
{
return stream >> listModel.m_items;
}
In order to serialize the contents of listModel.m_items (objects of type CListItem) I implemented the according operators in ListItem.h:
#ifndef _LISTITEM_
#define _LISTITEM_
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QDateTime>
#include <QtCore/QVariantMap>
class CListItem
{
public:
// ...
friend void operator <<(QVariant& data, const CListItem& target);
friend void operator >>(const QVariant& data, CListItem& target);
private:
QString m_name;
QString m_domain;
QString m_login;
QString m_password;
QDateTime m_LastModified;
};
#endif // !_LISTITEM_
and ListItem.cpp:
template<typename T>
void operator <<(QVariant& data, const T& target)
{
data = QVariant::fromValue<T>(target);
}
template<typename T>
void operator >>(const QVariant& data, T& target)
{
target = data.value<T>();
}
void operator <<(QVariant& data, const CListItem& target)
{
QVariantMap map;
map["name"] << target.m_name;
map["domain"] << target.m_domain;
map["login"] << target.m_login;
map["password"] << target.m_password;
map["dateModified"] << target.m_LastModified;
data << map;
}
void operator >>(const QVariant& data, CListItem& target)
{
QVariantMap map;
data >> map;
map["name"] >> target.m_name;
map["domain"] >> target.m_domain;
map["login"] >> target.m_login;
map["password"] >> target.m_password;
map["dateModified"] >> target.m_LastModified;
}
I fixed it.
The problem was that I didn't have operators to put my QList into a QDataStream. But I defined wrappers to store my list in QVariant, so (of course) I just should have used those.
QDataStream& operator <<(QDataStream& stream, const CListModel& listModel)
{
QVariant var;
var << listModel.m_items;
return stream << var;
}
QDataStream& operator >>(QDataStream& stream, CListModel& listModel)
{
QVariant var;
stream >> var;
var >> listModel.m_items;
return stream;
}
It looks like here is no operator<< overloaded for arguments: QDataStream & and QList<CListItem> const&. In the reference here and here, there aren't any documented.
The second error addresses this, but there also should be QList<CListItem> argument mentioned. Was that the full error message?
Basically, you should be using this:
QDataStream& operator <<(QDataStream& stream, const CListModel& listModel)
{
for(auto const& item : listModel.m_items)
stream << item; // write elements one by one
return stream;
}
This template might serve you for multiple types (or something akin to Pretty-print C++ STL containers):
template <typename Stream, typename Containter>
Stream& operator <<(Stream& stream, const Containter& container)
{
for(auto const& item : container)
stream << item;
return stream;
}
Your code would be valid without making change to operator<< you defined. Hope that helps.

Overloading input operation >> in header or .cpp

If i want to overload the operator ">>" and this is the line inside my .h file
friend istream &operator >> (istream& input,const Money&m2);
Do I want for instance
friend istream &operator >> (istream& input,const Money&m2){
input >> m2.dollar;
return input;
}
into my header file or into my class file. If i were to put it into my class file how would the function be called? Would something like this be okay?
const Money Money::&operator >> (istream& input,const Money&m2)
The class name is "Money.cpp"
The input streaming operator takes a reference to a non-const std::istream, and a reference to a non-const object into which the data is to be read. You can define it as a friend of the class for efficiency (direct access to the member variables), but if you already provide efficient mechanisms for setting those values, you may want to consider whether it needs to be a friend at all.
In the example below, I define a class Money, which represents some value (as a double-precision floating-point value, which is pretty bad, but just an example) and the ISO currency code (as a std::string). I then define an input streaming operator that reads input in the format "13.99 GBP" and an output streaming operator that writes the values in the same format.
Live example: http://coliru.stacked-crooked.com/a/d3e24b4fd697f773
money.hpp
class Money {
public:
Money(double value, const std::string& code);
const std::string& currencyCode() const;
double value() const;
friend std::istream& operator>>(std::istream&, Money&);
private:
double value_;
std::string code_;
};
std::istream& operator>>(std::istream& in, Money& m);
std::ostream& operator<<(std::ostream& out, const Money& m);
money.cpp
Money::Money(double value, const std::string& code)
: value_(value), code_(code) {}
const std::string& Money::currencyCode() const {
return code_;
}
double Money::value() const {
return value_;
}
std::istream& operator>>(std::istream& in, Money &m) {
in >> m.value_ >> m.code_;
return in;
}
std::ostream& operator<<(std::ostream& out, const Money& m) {
out << m.value() << " " << m.currencyCode();
return out;
}
Some points to bear in mind:
In general, the output streaming operator need not be a friend; there is usually a way to access the information it needs through the public member functions of the class, without losing efficiency.
The input streaming operator is a friend only for efficiency reasons; we can stream directly into the member variables.
For the input streaming operator, the second parameter (the object you're reading into) must not be const - an input operation changes the object being read into.
For the output streaming operator, the second parameter (the object you're writing out) should be const - an output operation should not change the object being written out.
If the constructor performs some non-trivial validation (e.g. checking that the std::string contains a valid ISO currency code), we should not bypass that validation by reading directly into the member variable in our input streaming operator. Instead, we should read into a local double and a local string, then construct a Money object, handing validation off to the already-written constructor (see the example below; the header is identical, except for removing the friend declaration from the class).
Live example: http://coliru.stacked-crooked.com/a/233ac7c17e51f612
money.cpp (validation in constructor)
Money::Money(double value, const std::string& code)
: value_(value), code_(code) {
if (code_ != "GBP") throw std::runtime_error("Must be GBP");
}
const std::string& Money::currencyCode() const {
return code_;
}
double Money::value() const {
return value_;
}
std::istream& operator>>(std::istream& in, Money &m) {
double value(0.0);
std::string code;
in >> value >> code;
m = Money(value, code);
return in;
}
std::ostream& operator<<(std::ostream& out, const Money& m) {
out << m.value() << " " << m.currencyCode();
return out;
}
If you put it in your header any change in the function definition requires recompilation of any files that include it. If you define it in the .cpp file then you don't and the linker will sort out calling it.
I don't know what is bothering you so have this example and see if it clears your doubt.
Run Here: http://ideone.com/K90L13
.h
#include <iostream>
#include <istream>
using namespace std;
class A{
int p;
public:
friend istream & operator >> (istream&,A&);
friend ostream & operator << (ostream&,A&);
};
.cpp
istream & operator >> (istream &input, A &obj){
input >> obj.p;
return input;
}
ostream & operator << (ostream &output, A &obj){
output << obj.p;
return output;
}
int main(){
A a;
cin >> a;
cout << a;
}
answered.
Function name in class field should be
std::istream &operator >> (istream& input,const Money&m2){}

Overloading operator for programming exercise

I'm in a programming class and need overloading explained to me. Simple question so hopefully I'll get an answer pretty quick. My understanding is that overloading an operator allows it to be used on a class. If that is true, then how would I overload >> to work with a class? I'm working on a small program to test out this idea and i'll post it here
#include <iostream>
#include <cstdlib>
#include "data.h"
using namespace std;
int main()
{
data obj;
cout << "What is the Number?" << endl;
cin >> obj;
system("pause");
return 0;
}
class data
{
public:
data operator >> (int);
private:
};
This page tells you mostly everything you need to know about operator overloading.
In short, nearly every operator in C++ can be overloaded for user-defined types. Some operators, like +, -, or >> must be defined outside of a class since they are free-standing, whereas others like copy assignment (=), must be defined within.
For your case, overloading the >> operator can be done in the following manner:
istream& operator>>(istream& in, data& d){
// Code here
return in;
}
Where it says "Code here", place the code you need to read into the data object.
For example, let us pretend that we were reading into a Point object with an x coordinate and a y coordinate. It is formatted in the stream like so: "(x,y)". The operator overload might look like this:
istream& operator>>(istream& in, Point& p){
char c;
in >> c;
if(c != '('){
in.clear(ios_base::failbit);
return in;
}
in >> p.x >> c >> p.y >> c;
return in;
}
This is just an example with minimal format checking, but hopefully it is enough to get you started.
Note that if members in your class are private, then you should friend the istream operator in the class definition:
class data{
...
public:
friend istream& operator>>(istream&, data&);
}
case1: no need to access private data
data.h.
class data {
public:
int i;
};
std::ostream& operator>> (std::istream&, data&); // better make operator >>
// a nonmember function
// if it doesn't need access
// to private data
data.cpp
#include "data.h"
std::istream& operator>> (std::istream& is, data& d) {
is>>d.i; // here we do some logic, we do what it means to do >> on
return is; // an instance of your data class and return reference to istream
}
case2: there is a need to access private data
data.h.
class data {
private:
int i;
friend std::ostream& operator>> (std::istream&, data&);
};
data.cpp
#include "data.h"
std::istream& operator>> (std::istream& is, data& d) {
is>>d.i; // here we do some logic, we do what it means to do >> on
return is; // an instance of your data class and return reference to istream
}
If you want to bolster your understanding of what operator overloading is, consider that essentially all operators on objects (such as "+", "++", "==", "!=", etc) are member functions.
Challenge yourself to recognize Obj a, b; a = b; as Obj a; Obj b; a.operator=(b);.
Overloading is purely providing a non-default implementation.
Here is a [terrible] overload of the cast-to-const-char* operator:
class BadWolf {
const char* m_text;
public:
BadWolf(const char* text) : m_text(text) {}
// if you really want the original text and ask for it with this function...
const char* tardisTranslation() const { return m_text; }
// but if you try to use me as a const char*...
operator const char* () const { return "bad wolf"; }
};
int main(int argc, const char* argv[]) {
BadWolf message("hello, sweetie");
std::cout << "Message reads: " << (const char*)message << std::endl;
std::cout << "Tardis translation: " << message.tardisTranslaction() << std::endl;
return 0;
}
I think this is what you want.
class data
{
friend istream& operator>>( istream&, data& );
private:
int data;
};
istream& operator>>( istream& in, data& d )
{
return in >> d.data;
}