How to write/read classes within classes to binary file C++ - c++

I'm working on a project where I have to write a class that contains three other classes as private member variables to a binary file, where it can then be read back into variables to be used in the code. The code writes to the file, but I don't know if it is writing the correct info as when I try to read the file it reads in junk. I have included my current setup, does this look correct? If so, what could be going wrong, and if not, how can I fix this?
If you need me to add any extra code, please ask. Another consideration is that two of the classes being used as member functions for the players objects inherit from other classes.
if (cFile.is_open())
{
cFile.seekp(ios::beg);
for (int i = 0; i < 3; i++)
{
cFile.write(reinterpret_cast<char *>(&players[i]), sizeof(Character));
}
cFile.seekg(ios::beg);
for (int i = 0; i < 3; i++)
{
cFile.read(reinterpret_cast<char *>(&playersRead[i]), sizeof(Character));
playersRead[i].display();
}
cFile.close();
}
else
{
cout << "Error opening file." << endl;
}
I've been working on this code for a few days and am really having trouble. I appreciate any help I can get, thanks in advance.
#pragma once
#include <iostream>
using std::ostream;
#include "string.h"
#include "coinPouch.h"
#include "backpack.h"
class Character
{
public:
Character();
Character(String name);
Character(String name, CoinPouch wallet, Backpack storage);
Character(const Character & copy);
~Character();
Character & operator =(const Character & rhs);
friend ostream & operator << (ostream & out, const Character & c);
void purchase(int p, int g, int s, int c);
void income(int p, int g, int s, int c);
void addPotion(const Potion & toAdd);
void checkBalance();
void checkBackpack();
void changeName(const String & newN);
void display();
String getName();
CoinPouch getWallet();
Backpack getStorage();
void setName(String name);
void setWallet(CoinPouch wallet);
void setStorage(Backpack storage);
private:
String m_name;
CoinPouch m_wallet;
Backpack m_storage;
};
#include "character.h"
using std::endl;
using std::cout;
Character::Character() : m_name("Player")
{
CoinPouch initialW;
Backpack initialS;
m_wallet = initialW;
m_storage = initialS;
}
Character::Character(String name) : m_name(name)
{
CoinPouch initialW;
Backpack initialS;
m_wallet = initialW;
m_storage = initialS;
}
Character::Character(String name, CoinPouch wallet, Backpack storage) : m_name(name), m_wallet(wallet), m_storage(storage)
{
}
Character::Character(const Character & copy) : m_name(copy.m_name), m_wallet(copy.m_wallet), m_storage(copy.m_storage)
{
}
Character::~Character()
{
}
Character & Character::operator =(const Character & rhs)
{
if (this != &rhs)
{
m_name = rhs.m_name;
m_wallet = rhs.m_wallet;
m_storage = rhs.m_storage;
}
return *this;
}
ostream & operator << (ostream & out, const Character & c)
{
out << c.m_name << ": " << endl;
out << c.m_wallet << endl;
out << c.m_storage << endl;
return out;
}
void Character::purchase(int p, int g, int s, int c)
{
m_wallet.buy(p, g, s, c);
}
void Character::income(int p, int g, int s, int c)
{
m_wallet.add(p, g, s, c);
}
void Character::addPotion(const Potion & toAdd)
{
m_storage.addPotion(toAdd);
}
void Character::checkBalance()
{
m_wallet.display();
}
void Character::checkBackpack()
{
m_storage.displayContents();
}
void Character::changeName(const String & newN)
{
m_name = newN;
}
void Character::display()
{
cout << m_name << ": " << endl;
m_wallet.display();
m_storage.displayContents();
}
String Character::getName()
{
return m_name;
}
CoinPouch Character::getWallet()
{
return m_wallet;
}
Backpack Character::getStorage()
{
return m_storage;
}
void Character::setName(String name)
{
m_name = name;
}
void Character::setWallet(CoinPouch wallet)
{
m_wallet = wallet;
}
void Character::setStorage(Backpack storage)
{
m_storage = storage;
}
#pragma once
#include <iostream>
using std::ostream;
#include "string.h"
class CoinPouch
{
public:
CoinPouch();
CoinPouch(String init);
CoinPouch(int p, int g, int s, int c);
CoinPouch(const CoinPouch & copy);
~CoinPouch();
CoinPouch & operator = (const CoinPouch & rhs);
friend ostream & operator << (ostream & out, const CoinPouch & c);
void add(int p, int g, int s, int c);
bool checkCost(int p, int g, int s, int c);
void buy(int p, int g, int s, int c);
void convertCost();
void roundUp();
void display();
int getP();
int getG();
int getS();
int getC();
private:
String m_amount;
int m_platinum;
int m_gold;
int m_silver;
int m_copper;
};
#pragma once
#include "potions.h"
class DynamicArray
{
public:
// Constructors
DynamicArray();
~DynamicArray();
DynamicArray(const DynamicArray & copy);
// Op Equals
DynamicArray & operator =(const DynamicArray & rhs);
// Insert, delete, and get elements functions
int getElements();
void Insert(const Potion & add);
void Delete(const Potion & rmv);
void display();
// Overloaded operators
Potion & operator [](int index);
friend ostream & operator << (ostream & out, const DynamicArray & d);
private:
// Member variables
Potion * m_array;
int m_elements;
// Find function
int Find(const Potion & target);
};
#pragma once
#include "string.h"
#include <iostream>
using std::ostream;
class Potion
{
public:
// Constructors
Potion();
Potion(String name, String description, String potency, String cost);
Potion & operator = (const Potion & rhs);
Potion(const Potion & copy);
// Desctructor
~Potion();
// Overloaded operators
bool operator == (const Potion & rhs) const;
friend ostream & operator << (ostream & out, const Potion & p);
// Getter functions
String getName();
String getDesc();
String getPotency();
String getCost();
int getP();
int getG();
int getS();
int getC();
// Setter functions
void setName(String name);
void setDesc(String desc);
void setPotency(String potency);
void setCost(String cost);
// Convert and display functions
void convertCost();
void display();
private:
// Strings to hold item information
String m_name;
String m_description;
String m_potency;
String m_cost;
// Ints to hold cost information
int m_platinum;
int m_gold;
int m_silver;
int m_copper;
// Logical test
bool m_isnull = false;
};
#pragma once
#include <iostream>
using std::ostream;
class String
{
public:
// Constructors
String();
String(char ch);
String(const char * str);
// Destructor
~String();
// Copy Constructor and Copy Assignment Constructor
String(const String & copy);
String & operator=(const String & rhs);
friend ostream & operator << (ostream & out, const String & s);
// Added Functionality
void display();
void upper();
void lower();
// Operator Conversion
operator char *();
operator const char *();
// Overloaded operator
bool operator == (const String & rhs) const;
private:
// Member variables
char * m_str;
int m_ischar;
};
#pragma once
#include "dynamicarray.h"
#include "coinPouch.h"
#include "string.h"
class Backpack
{
public:
Backpack();
Backpack(DynamicArray potions);
Backpack(const Backpack & copy);
~Backpack();
Backpack & operator = (const Backpack & rhs);
friend ostream & operator << (ostream & out, const Backpack & c);
void addPotion(const Potion & add);
void usePotion(const Potion & rm);
void displayContents();
private:
DynamicArray m_potions;
int m_number;
};
This is a school project, and I am supposed to write the Character class to a binary file in order to save the characters so I can load them in on the program start. Right now I'm just trying to make sure that they can be successfully written to and read from the binary file and I have had no luck.
My bad, didn't know what to post and I didn't want to post everything in my file. Here is the character class. Let me know what else is needed, if anything.

It should be immediately obvious that this code can't possibly work.
cFile.write(reinterpret_cast<char *>(&players[i]), sizeof(Character));
However big sizeof(Character) is, we could have a Character with an m_name that takes up more bytes than that. So this code can't possibly be writing the character's name, and it clearly needs to do that.
Before you write anything to a file, decide on (and ideally, document) a file format at the byte level. Make sure your code writes in the format you documented and also can read in the format you documented. Skipping this step leads to pain and it also makes debugging impossible because you can't look at the file and compare it to a specification to see whether the writer or the reader is at fault.
Had you documented what bytes the player's name will occupy in the file, you'd immediately realize that you either need to have a variable-length object and encode the length somehow or pick a largest size name and allocate those many bytes. But because you skipped that vital step, you never actually worked out how to write a Character to a file.

Related

c++ | << operator overloading and printing a string

I had a class name address:
#ifndef __ADRESS
#define __ADRESS
#include <iostream>
using namespace std;
class Adress
{
private:
std::string street;
int number;
std::string city;
public:
Adress(std::string name = "Hertzel", int number = 1, std::string city = "Tel Aviv"); //C'tor
Adress(const Adress& other); //cpy c'tor
Adress(Adress&& other);//Move c'tor
//Get methods
const string& getStreet() const;
int getNumber() const;
const string& getCity() const;
//Set methods
bool setStreet(std::string streetName);
bool setNumber(int num);
bool setCity(std::string cityName);
const Adress& operator=(const Adress& other);
friend ostream& operator<<(ostream& os, const Adress& adress);
};
#endif // !__ADRESS
The street and city were originally char* and now I changed it to strings.
But now I have a weird issue. While using char* I managed to use operator<< function inorder to print the content of address, now after switching to string instead char* when I try printing an address the program terminates.
This is the implementation I wrote for the function:
ostream& operator<<(ostream& os, const Adress& adress)
{
os << adress.street << " " << adress.number << " " << adress.city;
return os;
}
Is anyone familiar with that problem?
Thanks!
The error appears to be elsewhere. You didn't give any implementation file so I had to fill in a dummy implementation for the setters and I can't reproduce the error.
#ifndef ADDRESS_H
#define ADDRESS_H
#include <ostream>
#include <string>
class Adress{
private:
std::string street;
int number; //can this be negative or zero
std::string city;
public:
~Adress() = default;
Adress() : street("Hertzel"), number(1), city("Tel Aviv"){}
Adress(const Adress& other) = default;
Adress(Adress&& other) = default;
Adress& operator=(const Adress& other) = default;
//Get methods
const std::string& getStreet() const { return street; }
int getNumber() const { return number; }
const std::string& getCity() const{ return city; }
//Set methods
bool setStreet(std::string streetName) {
//check empty, is_alphanum etc
street = streetName;
return true;
}
bool setNumber(int num){
//check zero negative
number = num;
return true;
}
bool setCity(std::string cityName){
//checks here
city = cityName;
return true;
}
friend std::ostream& operator << (std::ostream& os, const Adress& adress);
};
inline std::ostream& operator << (std::ostream& os, const Adress& adress){
os << adress.street << " " << adress.number << " " << adress.city;
return os;
}
#endif
main
#include <iostream>
#include "address.hpp"
int main(int, char**){
Adress a;
std::cout << a << '\n';
}
Compiled with gcc-10 seems fine. Debugger time it appears

c++ destructor called before cout

#include <iostream>
#include <string.h>
using namespace std;
class Location
{
double lat, lon;
char *emi;
public:
Location(int =0, int=0, const char* =NULL);
~Location();
Location (const Location&);
void print () const;
friend ostream& operator<< (ostream&, const Location &);
void operator! ();
protected: ;
private:
};
Location::Location(int lat, int lon, const char *emi)
{
this->lat=lat;
this->lon=lon;
if (emi!=NULL)
{
this->emi=new char [strlen (emi)+1];
strcpy (this->emi, emi);
}
}
Location::~Location()
{
if (emi!=NULL)
delete []emi;
}
Location::Location(const Location &l)
{
lat=l.lat;
lon=l.lon;
if (l.emi!=NULL)
{
emi=new char [strlen (l.emi)+1];
strcpy (emi, l.emi);
}
}
void Location::operator! ()
{
if (!(strcmp(this->emi, "north")))
strcpy (this->emi, "south");
else strcpy (this->emi, "north");
}
void Location::print() const
{
cout<<this->emi<<endl;
cout<<this->lon<<endl;
cout<<this->lat<<endl;
cout<<endl;
}
class Adress
{
char *des;
Location l1;
char *country;
public:
Adress(char *,const Location &, char *);
virtual ~Adress();
friend ostream& operator<< (ostream&, const Adress &);
protected:
private:
};
Adress::Adress(char *des,const Location &l1, char *country)
{
if (des!=NULL)
{
this->des=new char [strlen (des)+1];
strcpy (this->des, des);
}
if (country!=NULL)
{
this->country=new char [strlen (country)+1];
strcpy (this->country, country);
}
this->l1=l1;
}
Adress::~Adress()
{
if (country!=NULL)
delete []country;
if (des!=NULL)
delete []des;
}
ostream& operator<< (ostream &os, const Adress& a){
os <<"Descrition: " << a.des<<endl;
os<<"Country: "<<a.country<<endl;
a.l1.print();
return os;
}
int main ()
{
Adress a1 ("dsad", Location (323, 34, "fdsf"), "fsdf");
cout<<a1;
}
The problem is that when I create an Adress object and display it, all the fields are correct , but the "emi" which is messed up, showing a random character. I think the destructor is called before I display it. If I remove the Location destructor it works. How should I resolve it? I'm sorry for my mistakes but I am a newbie.
First of all, it would be better to use std::string rather than char* but I will explain your problem for the education goal.
You must ensure after constructing an object, all of its member variables are initialized. In the case of Location class for example; you did not initialize the emi member variable if the third argument of the constructor is nullptr. so I changed it a little:
Location::Location(int _lat, int _lon, const char* _emi)
: lat(_lat)
, lon(_lon)
, emi(nullptr)
{
if (_emi != nullptr)
{
emi = new char[strlen(_emi) + 1];
strcpy(emi, _emi);
}
}
Next, you have a raw pointer in your class and you can not simply copy or assign it. You have to implement the assignment operator as well as the copy constructor.
Location& Location::operator=(const Location& other)
{
if (this != &other)
{
lat = other.lat;
lon = other.lon;
if (emi) delete[] emi;
emi = new char[strlen(other.emi) + 1];
strcpy(emi, other.emi);
}
return *this;
}

reverse function doesn't reverse the referenced string of a class instantiation

I'm trying to reverse the string from the FunnyNumber class. The problem is that when I call the method reverse in main on f2, it doesn't reverse the f2 string. But when I print out the reversed string from the reverse method implementation, it works. Also I overloaded the << operator to print out the string value in the class Number which is inherited in FunnyNumber class. Any help would be appreciated.
#ifndef NUMBER_H
#define NUMBER_H
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
class Number {
public:
// Make a number with value 0
Number();
// Make a number with value val
Number(string val);
// Get the number's value
virtual string getValue() const;
// Print this number to the stream
virtual void print(ostream& stream) const;
// Read this number from the stream
virtual void read(istream& stream);
// Overload the insertion operator
friend ostream& operator <<(ostream& outs, const Number& n);
// Overload the extraction operator
friend istream& operator >> (istream& ins, Number& n);
protected:
string value;
};
#endif
Number::Number()
{
value = "";
}
Number::Number(string args)
{
value = args;
}
string Number::getValue()const
{
return value;
}
ostream& operator <<(ostream& outs, const Number& n)
{
n.print(outs);
return outs;
}
void Number::print(ostream& stream)const
{
stream << getValue();
}
void Number::read(istream& stream)
{
stream >> value;
}
istream& operator >> (istream& ins, Number& n)
{
n.read(ins);
return ins;
}
#ifndef FUNNYNUMBER_H
#define FUNNYNUMBER_H
#include<iostream>
#include<string>
#include"Number.h"
#include<algorithm>
using namespace std;
class FunnyNumber : public Number
{
public:
FunnyNumber();
FunnyNumber(string val);
virtual string operator+(const FunnyNumber &other)const;
virtual bool operator==(const FunnyNumber &other)const;
void reverse();
int find_first_not_this(char a);
protected:
string value;
};
#endif // !FUNNYNUMBERS_H
FunnyNumber::FunnyNumber()
{
value = "";
}
FunnyNumber::FunnyNumber(string val) : Number(val)
{
value = val;
}
string FunnyNumber::operator+ (const FunnyNumber& other)const
{
return getValue() + other.getValue();
}
int FunnyNumber::find_first_not_this(char a)
{
int pos = 0;
for(int i = 0; i < value.length(); i++)
{
if(value[i] != a)
{
pos = i;
return pos;
}
}
return pos;
}
bool FunnyNumber::operator==(const FunnyNumber& other)const
{
bool isEqual = true;
for (int i = 0; i < other.getValue().length(); i++)
{
bool found = false;
for (int j = 0; j < getValue().length(); j++)
{
if(getValue()[j] == other.getValue()[i])
{
found = true;
break;
}
}
if(!found)
{
isEqual = found;
return isEqual;
}
}
return isEqual;
}
void FunnyNumber::reverse()
{
std::reverse(value.begin(), value.end());
value.erase(0, find_first_not_this('0'));
}
#include <iostream>
#include<string.h>
#include "FunnyNumber.h"
using namespace std;
int main()
{
FunnyNumber f2;
f2 = FunnyNumber("223");
f2.reverse();
cout<<"Reversed value "<<f2<<endl;
system("pause");
return 0;
}
output is 223 instead of 322
Your FunnyNumber stores the value twice, once in a subobject of type Number, and once in string FunnyNumber::value.
Your reverse function modifies the second one, but doesn't have any effect on the Number base subobject. And then the only output function you call is working on the Number base subobject, and knows nothing about string FunnyNumber::value. That's why what is printed is not the result of reversal.
the overloaded operator << is a friend function on the Number class and friend functions are not inherited.
class Number {
public:
// Make a number with value 0
Number();
// Make a number with value val
Number(string &val);
// Get the number's value
virtual string getValue() const;
// Print this number to the stream
virtual void print(ostream& stream) const;
// Read this number from the stream
virtual void read(istream& stream);
// Overload the insertion operator
friend ostream& operator <<(ostream& outs, const Number& n);
// Overload the extraction operator
friend istream& operator >> (istream& ins, Number& n);
protected:
string *value;
};
Number::Number()
{
value = NULL;
}
Number::Number(string &args)
{
value = &args;
}
string Number::getValue()const
{
return *value;
}
ostream& operator <<(ostream& outs, const Number& n)
{
n.print(outs);
return outs;
}
void Number::print(ostream& stream)const
{
stream << getValue();
}
void Number::read(istream& stream)
{
stream >> *value;
}
istream& operator >> (istream& ins, Number& n)
{
n.read(ins);
return ins;
}

\main.cpp|103|error: no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'Person')

this is my first question so please bear with any formatting mistakes i make, I'll try to edit them :)
I've got this function which finds the max of three variables of some data type X and returns it.
template <class X>
X fmax(X a, X b, X c)
{
X temp=a;
if (b>temp)
temp=b;
if(c>temp)
temp=c;
return temp;
}
Then there is the class Person which looks like this
class Person
{
private:
char* name;
int height;
char gender;
public:
Person(){}
Person(char * name,int height, char gender)
{
int sz=strlen(name);
this->name= new char [sz];
strcpy(this->name,name);
this->height=height;
this->gender=gender;
}
void setName(char* name)
{
int sz=strlen(name);
this->name= new char [sz];
strcpy(this->name,name);
}
void setHeight(int h){this->height=h;}
void setGender(char g){this->gender=g;}
char* getName(){return this->name;}
int getHeight(){return this->height;}
char getGender(){return this->gender;}
Person operator= (Person p)
{
int sz=strlen(p.getName());
this->name= new char [sz];
strcpy(this->name,p.getName());
this->height=p.getHeight();
this->gender=p.getGender();
return *this;
}
bool operator> (Person p)
{
if(this->getHeight()>p.getHeight())//The persons should be compared using their heights.
return true;
return false;
}
};
and I also overloaded the ostream:
ostream &operator<<(ostream &mystream, Person &p)
{
mystream<<"The person's name is: "<<p.getName()<<endl;
mystream<<"The person's height is: "<<p.getHeight()<<endl;
mystream<<"The person's gender is: "<<p.getGender()<<endl;
return mystream;
}
But I'm getting the error in my main:
int main()
{
Person a("Zacky",178,'m');
Person b("Jimmy",199,'m');
Person c("Matt",200,'m');
Person d=fmax(a,b,c);
cout<<d<<endl;
cout<<fmax(a,b,c);<<endl;//the error strikes here.
return 0;
}
Apparently I can cout the object d after i've initialised it using the fmax function but can't directly cout what is returned by the function. Any idea about what I need to fix?
P.S. I'm totally sorry if this was asked before, I searched the site and didn't find something similar :/
You need to change the following things:
Since fmax() returns an unchangable rvalue you should use
ostream &operator<<(ostream &mystream, const Person &p);
// ^^^^^
as signature for the output operator overloading (I would recommend doing that in general).
That in turn would require to make your getter functions const member functions:
class Person
{
// ...
const char* getName() const {return this->name;}
int getHeight() const {return this->height;}
char getGender() const {return this->gender;}
};

std::map key not found even though the entries are identical

I'm learning C++ and I've been writing a wrapper for std::map and std::string, and I've stumbled upon a problem. Whenever I add something to the map using a string as key, once I try to access that item using the exact same key it says the key is out of bounds of the map. Here's my code (irrelevant parts left out):
ADictionary.h
#ifndef ADICTIONARY_H
#define ADICTIONARY_H
#include <map>
...
template<typename KEY, typename VALUE>
class ADictionary {
public:
...
VALUE operator [](KEY key) const {
return value.at(key);
}
void add(KEY key, VALUE value) {
this->value.insert(std::make_pair(key, value));
}
...
private:
std::map<KEY, VALUE> value;
};
#endif
AString.cpp
#include "AString.h"
AString::AString() {
value = "";
}
AString::AString(const char character) {
value = character;
}
AString::AString(const char * characters) {
value = characters;
}
AString::AString(std::string text) {
value = text;
}
...
AString::operator const char *() const {
return value.c_str();
}
AString::operator const std::string() const {
return value;
}
...
ABoolean AString::operator<(AString & text) const {
return getLength() < text.getLength();
}
ABoolean AString::operator>(AString & text) const {
return text < *this;
}
ABoolean AString::operator==(AString & text) const {
return value == text.value;
}
ABoolean AString::operator!=(AString & text) const {
return !(text == *this);
}
AString & AString::operator=(AString & text) {
value = text.value;
return *this;
}
...
The code which uses the above
ADictionary<AString, AString> test;
AString a = "a";
AString b = "b";
test.add(a, b);
std::cout << test[a]; // Error occurs here, according to the program "a" is not a key in the map
I hope someone can explain to me what's going wrong. I've tried creating a dictionary with the default std::string as types and it worked correctly:
ADictionary<std::string, std::string> test;
std::string a = "a";
std::string b = "b";
test.add(a, b);
std::cout << test[a]; // No error this time
As I've said, I'm pretty new to C++ so there may be other errors. If so, feel free to point them out.
Thanks!
EDIT:
AString.h
#ifndef ASTRING_H
#define ASTRING_H
#include <string>
#include "ABoolean.h"
#include "AInteger.h"
#include "AList.h"
class ABoolean;
class AInteger;
template<typename VALUE>
class AList;
class AString {
public:
AString();
AString(const char);
AString(const char *);
AString(std::string);
~AString();
operator const char *() const;
operator const std::string() const;
operator const AInteger() const;
ABoolean operator<(AString &) const;
ABoolean operator>(AString &) const;
ABoolean operator==(AString &) const;
ABoolean operator!=(AString &) const;
AString & operator=(AString &);
AString & operator+(AString &);
AString & operator+=(AString &);
void clear();
ABoolean contains(AString) const;
AInteger getIndex(AString) const;
AInteger getLength() const;
AList<AString> getSplit(AString) const;
AString getSubstring(AInteger, AInteger) const;
void removeRange(AInteger, AInteger);
void removeSubstring(AString);
void toLowercase();
void toUppercase();
private:
std::string value;
};
AString & operator+(const char, AString &);
AString & operator+(const char *, AString &);
#endif
Your string operators appear to be incorrect.
std::map uses the less than operator by default. While you provide one for AString, the only thing it does is check the length of the string. What if the two strings are of equal length?
The correct thing to do is to lexicographically compare the characters in the string. While there is a standard library function to do this, you can use operator < of the std::string values in your class:
friend bool operator<(AString const& a, AString const& b)
{
return a.value < b.value;
}
EDIT: You may also wish to remove your conversion operators, or at least make them explicit, which prevents surprising and unwanted implicit conversions. Constructors taking one parameter (other than copy or move constructors) should also be declared explicit.