Why is my operator<< overloading not working? - c++

Error:
..\Record.cpp: In function `std::ostream& operator<<(std::ostream&, Record&)':
..\Record.cpp:83: error: no match for 'operator<<' in 'out << Record::date()()'
Record.cpp:
/*
* Record.cpp
*
* Created on: Jun 13, 2010
* Author: DJ
*/
#include <iostream>
#include "Record.h"
using std::string;
using std::istream;
using std::ostream;
Record::Record() {
}
Record::Record(Date inDate) {
_date = inDate;
}
Record::Record(Date inDate, Time inTime) {
_date = inDate;
_time = inTime;
}
Record::Record(Date inDate, Time inTime, string inDescription) {
_date = inDate;
_time = inTime;
_description = inDescription;
}
Record::~Record() {
}
Time Record::time() {
return _time;
}
void Record::time(Time inTime) {
_time = inTime;
}
Date Record::date() {
return _date;
}
void Record::date(Date inDate) {
_date = inDate;
}
string Record::description() {
return _description;
}
void Record::description(string inDescription) {
_description = inDescription;
}
void Record::operator=(Record record) {
_date = record.date();
_time = record.time();
_description = record.description();
}
istream &operator>>(istream &in, Record &record) {
Time inTime;
Date inDate;
string inDescription;
in >> inDate >> inTime >> inDescription;
record.date(inDate);
record.time(inTime);
record.description(inDescription);
return in;
}
ostream &operator<<(ostream &out, Record &record) {
out << record.date() << " " << record.time() << " " << record.description();
return out;
}
Date.cpp:
/*
* Date.cpp
*
* Created on: Jun 13, 2010
* Author: DJ
*/
#include "Date.h"
#include <iostream>
using std::istream;
using std::ostream;
Date::Date() {
_day = 1;
_month = 1;
_year = 1999;
}
Date::Date(unsigned int inDay) {
day(inDay);
_month = 1;
_year = 1999;
}
Date::Date(unsigned int inDay, unsigned int inMonth) {
day(inDay);
month(inMonth);
_year = 1999;
}
Date::Date(unsigned int inDay, unsigned int inMonth, unsigned int inYear) {
day(inDay);
month(inMonth);
year(inYear);
}
Date::~Date() {
}
void Date::day(unsigned int inDay) {
assert(inDay <= daysInMonth());
_day = inDay;
}
unsigned int Date::day() {
return _day;
}
void Date::month(unsigned int inMonth) {
assert(inMonth <= 12);
_month = inMonth;
}
unsigned int Date::month() {
return _month;
}
void Date::year(unsigned int inYear) {
_year = inYear;
}
unsigned int Date::year() {
return _year;
}
void Date::operator=(Date date) {
day(date.day());
month(date.month());
year(date.year());
}
istream &operator>>(istream &in, Date &date) {
char dummy;
unsigned int day, month, year;
in >> month >> dummy >> day >> dummy >> year;
date.day(day);
date.month(month);
date.year(year);
return in;
}
ostream &operator<<(ostream &out, Date &date) {
out << date.month() << "/" << date.day() << "/" << date.year();
return out;
}
unsigned int Date::daysInMonth() {
if(_month == 1 || _month == 3 || _month == 5 || _month == 7 || _month == 8 || _month == 10 || _month == 12)
return 31;
else
return 30;
}
Time is basically the same as date.

Your operator<< should take const references (const Date &).
If your operators take non-const references, they won't work with temporary objects (such as the one returned from Record::date). This is what's causing the error.
Note that changing to const references means you will need to change any member functions called (e.g. Date::month) to be const. This is good practice anyway.
Another option is to pass the parameter by value, which will invoke the copy constructor. const references are usually preferred because they are generally faster, and you shouldn't need to invoke non-const members anyway.

Because the reading operator needs "read-only" access to the variable :
ostream &operator<<(ostream &out, const Record &record) //<< const
ostream &operator<<(ostream &out, const Date &date) //<< const
Here are some explanations about member function constness, as you'll have to make sure some accessors are const : http://www.parashift.com/c++-faq-lite/const-correctness.html

Related

Comparing data in array of objects using a member boolean function

First I need to compare the date of births in the array with the operator== function which is in the class Person, and also show the person with the earliest date of birth with the operator< function which is also in class Person. But I have trouble understanding what I'm doing wrong.
I was thinking of showing the earliest date of birth operator< using the same way as I did with operator== but now that it doesn't work, I have no idea.
#include <iostream>
#include <string>
using namespace std;
class Birth_date
{
private:
unsigned int day{};
unsigned int month{};
unsigned int year{};
public:
Birth_date() {}
Birth_date(int day, int month, int year)
{
this->day = day;
this->month = month;
this->year = year;
}
Birth_date(const Birth_date& birth)
{
day = birth.day;
month = birth.month;
year = birth.year;
}
void set_day(int day)
{
this->day = day;
}
void set_month(int month)
{
this->month = month;
}
void set_year(int year)
{
this->year = year;
}
int get_day()
{
return day;
}
int get_month()
{
return month;
}
int get_year()
{
return year;
}
friend bool operator == (const Birth_date& a, const Birth_date& b)
{
return (a == b);
}
bool operator < (const Birth_date& bd)
{
return day < bd.day && month < bd.month && year < bd.year;
}
bool operator > (const Birth_date& bd)
{
return day > bd.day && month > bd.month && year > bd.year;
}
ostream& Output(ostream& out)
{
out << "Date of birth: " << day << "/" << month << "/" << year << endl;
return out;
}
};
class Person
{
private:
string name;
Birth_date dob;
public:
Person() {}
Person(string name, Birth_date dob)
{
this->name = name;
this->dob = dob;
}
Person(const Person& p)
{
name = p.name;
dob = p.dob;
}
string get_name()
{
return name;
}
Birth_date get_dob()
{
return dob;
}
bool operator < (const Person& p)const
{
Birth_date bd1 = p.dob;
Birth_date bd2 = p.dob;
return (bd1 < bd2);
}
bool operator == (const Person& p)const
{
return (dob == p.dob);
}
const ostream& output(ostream& out)
{
out << "Name: " << name << "\t" ;
dob.Output(out);
return out;
}
};
int main()
{
Person students[5] = { Person("Ivan Petkov",Birth_date(10,6,1999)),
Person("Gabe Trent",Birth_date(20,12,1996)),
Person("Maggy Sommer",Birth_date(5,2,2000)),
Person("Cameron Dallas",Birth_date(1,4,2001)),
Person("Catherine Crumb",Birth_date(28,8,2000)) };
for (int i = 0; i < 5; i++)
{
students[i].output(cout);
}
cout << "\n";
for (int i = 0; i < 5; i++)
{
for (int x = i + 1; x < 5; x++)
{
if (students[i].operator==(students[x]))
{
cout << "Students " << students[i].get_name()
<< "and " << students[x].get_name()
<< "have the same date of birth." << endl;
}
else
cout << "Nobody has the same date of birth." << endl;
}
}
return 0;
}
Right now the only output is the array and then the program just exits.
When you're comparing dates there's the possibility that the year and the month are the same but the day is different.
21/4/2003 > 20/4/2003
however in your code you check that the month and year are greater and can't be equal.
return day < bd.day && month < bd.month && year < bd.year;
by your code if the dates are: 29/1/2000 and 1/3/2000 it would return false.
your functions should first check if the years are not the same, if they are then you next check the months and then the days.
Here's an example of a code I once wrote:
bool MyDate::operator >(const MyDate& d)const {
if (year < d.year)
return false;
else if (year > d.year)
return true;
else if (year == d.year) {
if (month < d.month)
return false;
else if (month > d.month)
return true;
if (month == d.month) {
if (day < d.day)
return false;
else if (day > d.day)
return true;
else
return false;
}
}
return true;
}

Compilation error in C++ when using an assignment operator =?

I have written a program which was given to me as a homework assignment (it's a bit longer). The issue is that it compiles in CodeBlocks but it does not compile in Visual Studio 2017 it says - binary '=': no operator found which takes a right-hand operand of type 'CAutomobile' (or there is no acceptable conversion.
I would like to ask why is that because I could not myself find the error? I tried commenting the operator =function but still the error remained.
#include <iostream>
#include <algorithm>
#include <string>
#include <stdlib.h>
using namespace std;
class CVehicle {
string name;
int year;
public:
CVehicle() {
name = "Car";
year = 1990;
}
CVehicle(string n, int y) {
name = n;
year = y;
}
CVehicle(const CVehicle& vc) {
name = vc.name;
year = vc.year;
}
void setName(string n) {
name = n;
}
void setYear(int y) {
year = y;
}
string getName() {
return name;
}
int& getYear() {
return year;
}
virtual void Print(ostream& os) = 0;
};
class CAutomobile :public CVehicle {
double litres;
public:
CAutomobile() :CVehicle() {
litres = 7.2;
}
CAutomobile(string nm, int yr, double l) :CVehicle(nm, yr) {
litres = l;
}
void setLitres(double l) {
l = litres;
}
double& getLitres() {
return litres;
}
void Print(ostream& os) override {
os << getName() << endl;
os << getYear() << endl;
os << litres << endl;
}
friend bool operator< (CAutomobile a1, CAutomobile a2) {
if (a1.litres < a2.litres) {
return true;
}
return false;
}
CAutomobile operator= (CAutomobile& at) {
CAutomobile au;
au.getName() = at.getName();
au.getYear() = at.getYear();
au.getLitres() = at.getLitres();
return au;
}
CAutomobile operator+(CAutomobile aut) {
CAutomobile a;
a.getLitres() = getLitres() + aut.getLitres();
return a;
}
friend ostream& operator<< (ostream& o, CAutomobile a) {
o << a.getName() << endl;
o << a.getYear() << endl;
o << a.getLitres() << endl;
return o;
}
};
int main()
{
CAutomobile a[] = {
CAutomobile(),
CAutomobile("Wolkswagen",1970,80.5),
CAutomobile("Fiat",1979,21.9),
CAutomobile("Opel",1978,13.7)
};
for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++) {
cout << "Name" << ' ' << a[i].getName() << endl;
cout << "Year" << ' ' << a[i].getYear() << endl;
cout << "Litres" << ' ' << a[i].getLitres() << endl;
}
int range = 2016 - 1990 + 1;
for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++) {
a[i].setLitres(rand() % 100 + 1);
a[i].setYear(rand() % range + 1996);
}
//сортираме масива по литри и извеждаме
//най малкия (първия) му елемент
for (int i = 0; i < sizeof(a-1); i++) {
for (int j = 0; j < sizeof(a-1); j++) {
if (a[j].getLitres() > a[j + 1].getLitres()) {
swap(a[j], a[j + 1]);
}
}
}
cout << a[0] << endl;
CAutomobile k = a[0] + a[3];
cout << k.getLitres() << endl;
}
CAutomobile::operator = is completely wrong. It takes a non-const reference and assignes its field to a new object. Instead it should take a const reference and modify current object.
CAutomobile & operator =(CAutomobile const & other)
{
assert(this != ::std::addressof(other)); // check for self-assignment
SetName(other.getName());
SetYear(other.getYear());
SetLitres(other.getLitres());
return *this;
}
This will bring up another problem: getters are not const-qualified, so they should be fixes as well:
string const & getName(void) const {
return name;
}
int const & getYear(void) const {
return year;
}

Segmentation Fault when trying to create a dynamically allocated char array

This is my code:
#include<iostream>
#include<string.h>
using namespace std;
class Zichara
{
private:
char *name;
int price;
void copy(const Zichara &from)
{
name = new char[strlen(from.name) + 1];
strcpy(name, from.name);
price = from.price;
}
public:
Zichara(const char *name, int price) {
this->name = new char[strlen(name) + 1];
strcpy(this->name, name);
this->price = price;
}
Zichara(const Zichara &from)
{
copy(from);
}
~Zichara() {
delete [] name;
}
friend class PlaninarskiDom;
};
class PlaninarskiDom {
private:
char name[15];
int prices[2];
char star;
bool isZichara;
Zichara *zich;
void copy(const PlaninarskiDom &from) {
strcpy(name, from.name);
star = from.star;
isZichara = from.isZichara;
zich = from.zich;
for(int i = 0; i < 2; i++) {
prices[i] = from.prices[i];
}
}
public:
PlaninarskiDom(const char *name = "", int prices = 0, const char star = '\0') {
strcpy(this->name, name);
this->star = star;
isZichara = 0;
zich = 0;
this->prices[0] = 0;
this->prices[1] = 0;
}
PlaninarskiDom(const char *name, int *prices, const char star) {
strcpy(this->name, name);
this->star = star;
isZichara = 0;
zich = 0;
this->prices[0] = prices[0];
this->prices[1] = prices[1];
}
PlaninarskiDom(const PlaninarskiDom &from) {
copy(from);
}
~PlaninarskiDom() {
delete [] zich;
}
PlaninarskiDom& operator = (const PlaninarskiDom &from) {
if(this == &from) return *this;
delete [] zich;
copy(from);
return *this;
}
void setZichara(Zichara &z) {
if(isZichara == 0) {
zich->copy(z);
isZichara = 1;
}
}
void operator --() {
if((int)star >= 65 && (int)star <= 70) {
++star;
if((int)star == 69) {
++star;
}
}
}
bool operator <= (char c) {
return star >= c;
}
void presmetajDnevenPrestoj(int day, int month, int &price) {
if(day < 0 || day > 31 || month < 0 || month > 12) {
throw 99;
}
else if(month >= 4 && month <= 8) {
price = prices[0];
}
else {
price = prices[1];
}
if(isZichara) {
price += zich->price;
}
}
friend ostream& operator << (ostream &, const PlaninarskiDom &);
};
ostream& operator << (ostream &os, const PlaninarskiDom &rhs) {
cout << rhs.name << " klasa:" << rhs.star << endl;
if(rhs.isZichara) {
cout << " so zichara" << endl;
}
return os;
}
int main(){
PlaninarskiDom p; //креирање на нов објект од класата планинарски дом
//во следниот дел се вчитуваат информации за планинарскиот дом
char imePlaninarskiDom[15],mestoZichara[30],klasa;
int ceni[12];
int dnevnakartaZichara;
bool daliZichara;
cin>>imePlaninarskiDom;
for (int i=0;i<2;i++) cin>>ceni[i];
cin>>klasa;
cin>>daliZichara;
//во следниот дел се внесуваат информации и за жичарата ако постои
if (daliZichara) {
cin>>mestoZichara>>dnevnakartaZichara;
PlaninarskiDom pom(imePlaninarskiDom,ceni,klasa);
Zichara r(mestoZichara,dnevnakartaZichara);
pom.setZichara(r);
p=pom;
}
else{
PlaninarskiDom *pok=new PlaninarskiDom(imePlaninarskiDom,ceni,klasa);
p=*pok;
}
//се намалува класата на планинарскиот дом за 2
--p;
--p;
int cena;
int den,mesec;
cin>>den>>mesec;
try{
p.presmetajDnevenPrestoj(den,mesec,cena); //тука се користи функцијата presmetajDnevenPrestoj
cout<<"Informacii za PlaninarskiDomot:"<<endl;
cout<<p;
if (p<='D')
cout<<"Planinarskiot dom za koj se vneseni informaciite ima klasa poniska ili ista so D\n";
cout<<"Cenata za "<<den<<"."<<mesec<<" e "<<cena; //се печати цената за дадениот ден и месец
}
catch (int){
cout<<"Mesecot ili denot e greshno vnesen!";
}
}
I ran a debugger on this code and it highlighted this:
name = new char[strlen(from.name) + 1];
This is the line of code as the line where the Seg Fault comes from.
This is an exercise for a class I have and I have to do it using dynamic memory allocation.
I've done this exact same thing many times before and there was no such error, so I have no idea why it is appearing, and I couldn't find an answer to this question on Google so far, so I apologize if somewhere out there it does exist.
Thanks everyone for the suggestions, this has been fixed!
You call this method:
void setZichara(Zichara &z) {
if(isZichara == 0) {
zich->copy(z);
isZichara = 1;
}
}
but you never allocate zich so you invoke UB calling a method on nullptr
Note: your PlaninarskiDom::copy() is incorrect as well, as you just assign pointer from another object aka shallow copy, which will lead to multiple destruction, though most probably you did not hit this issue yet. You should do deep copy instead or use std::shared_ptr is you plan to share ownership. Anyway if you are not limited by conditions using smart pointers are preferable when dealing with dynamically allocated objects. Or using special containers like std::vector or std::string which do proper memory management for you.

C++ Operand types are incompatible("Movie" and "nullptr")

const Movie* Movies::getMovie(string mc, int& mn) const {
if(mc.length()==0)
return nullptr; // not found
else {
mc = myToLower(mc);
int ndx=0;
for(;ndx<movieCnt &&
(myToLower(movies[ndx].getTitle()).find(mc)==
string::npos);ndx++);
mn = ndx<movieCnt?ndx+1:0;
return ndx<movieCnt?&movies[ndx]:nullptr;
}
}
//const Movie* Movies::getMovie(int mc) const {
const Movie* Movies::operator[](int mc) const{
return (mc > 0 && mc <= movieCnt)?movies[mc-1]:nullptr;
}
I got this error message error: Operand types are incompatible("Movie" and "nullptr")
In Movies.h
public:
Movies(string);
int getMovieCount() const;
const Movie* getMovie(string, int&) const;
const Movie* getMovie(int) const;
const Movie* Movies::operator[](int mc) const;
~Movies();
Any help? Thank you!
// Movie.cpp
#include "Movie.h" // include Movie class definition
#include <sstream>
using namespace std;
Movie::Movie() {
title = studio = "";
boxOffice[WORLD] = boxOffice[US] = boxOffice[NON_US] =
rank[WORLD] = rank[US] = rank[NON_US] = releaseYear = 0;
}
Movie::Movie(string temp) {
istringstream iS(temp);
getline(iS, title, '\t');
getline(iS, studio, '\t');
iS >> releaseYear >> rank[US] >> boxOffice[US] >> rank[NON_US]
>> boxOffice[NON_US] >> rank[WORLD] >> boxOffice[WORLD];
}
string Movie::getTitle() const {return title;}
string Movie::getStudio() const {return studio;}
int Movie::getReleaseYear() const {return releaseYear;}
int Movie::getUSRank() const {return rank[US];}
int Movie::getNonUSRank() const {return rank[NON_US];}
int Movie::getWorldRank() const {return rank[WORLD];}
long long Movie::getUSBoxOffice() const {return boxOffice[US];}
long long Movie::getNonUSBoxOffice() const {return boxOffice[NON_US];}
long long Movie::getWorldBoxOffice() const {return boxOffice[WORLD];}
std::ostream& operator << (std::ostream& os, const Movie &movie)
{
os << "\n\n====================== Movie Information\n"
<< "\n Movie Title:\t" << movie.getTitle()
<< " (" << movie.getReleaseYear() << ") " << movie.getStudio()
<< "\n US Rank & Box Office:\t" << movie.getUSRank() << "\t$" << movie.getUSBoxOffice()
<< "\nNon-US Rank & Box Office:\t" << movie.getNonUSRank() << "\t$" << movie.getNonUSBoxOffice()
<< "\n World Rank & Box Office:\t" << movie.getWorldRank()<< "\t$" << movie.getWorldBoxOffice()
<< "\n";
return os;
}
Movie::Movie(const Movie &mP) { // copy constructor
this->title = mP.title;
this->studio = mP.studio;
this->releaseYear = mP.releaseYear;
this->rank[US] = mP.rank[US];
this->rank[NON_US] = mP.rank[NON_US];
this->rank[WORLD] = mP.rank[WORLD];
this->boxOffice[US] = mP.boxOffice[US];
this->boxOffice[NON_US] = mP.boxOffice[NON_US];
this->boxOffice[WORLD] = mP.boxOffice[WORLD];
}
this is Movie.cpp,below is Movies.cpp.
// Movies.cpp
#include "Movie.h" // include Movie class definition
#include "Movies.h" // include Movies class definition
#include <fstream>
using namespace std;
Movies::Movies(string fn){loadMovies(fn);}
int Movies::getMovieCount() const {return movieCnt;}
const Movie* Movies::getMovie(string mc, int& mn) const {
if(mc.length()==0)
return nullptr; // not found
else {
mc = myToLower(mc);
int ndx=0;
for(;ndx<movieCnt &&
(myToLower(movies[ndx].getTitle()).find(mc)==
string::npos);ndx++);
mn = ndx<movieCnt?ndx+1:0;
return ndx<movieCnt?&movies[ndx]:nullptr;
}
}
//const Movie* Movies::getMovie(int mc) const {
const Movie* Movies::operator[](int mc) const{
return (mc > 0 && mc <= movieCnt)?&movies[mc-1]:nullptr;
}
Movies::~Movies() { // not needed - invoked at end
delete[] movies;
movies = nullptr;
}
void Movies::loadMovies(string fn) {
ifstream iS(fn);
string s;
getline(iS, s); // skip heading
getline(iS, s);
movieCnt=0;
movies = new Movie[MAX_MOVIES];
while(!iS.eof()) {
movies[movieCnt++] = Movie(s);
getline(iS, s);
}
iS.close();
reSize();
}
void Movies::reSize() {
Movie * m = movies;
movies = new Movie[movieCnt];
for(int i=0;i<movieCnt;i++)
movies[i] = m[i];
delete[] m; // null assignment not needed; end of method
}
string Movies::myToLower(string s) const {
string t; // initialized as ""
for(char c : s)
t += tolower(c);
return t;
}
a part of Movies.h:
public:
Movies(string);
int getMovieCount() const;
const Movie* getMovie(string, int&) const;
const Movie* getMovie(int) const;
const Movie* Movies::operator[](int) const;
~Movies();
#WhozCraig Thank you for answering me! I upload the Movie.cpp,Movies.cpp and part of Movies.cpp I really conused..

Printing out information from a file by looping through another function designed to search the file - C++

I have this function that can scan my file and print out a predesignated record according to which one you choose to look at:
void addressBook::showRecord(int pickNum) {
PEOPLE2 p;
ifstream indata("vectortest.dat", ios::binary);
if(!indata) {
cout << "Error opening file for reading " << endl;
exit(0);
}
indata.seekg(pickNum * sizeof(PEOPLE2));
indata.read(reinterpret_cast <char*> (&p), sizeof(PEOPLE2));
cout << p.fName2 << " " << p.lName2 << " " << p.Address2 << " " << endl;
}
So all you have to do is pop showRecord into main, and then pick which name you want to print out. Say I want to look at the second name stored, I would put in
newBook->showRecord(1);
Thats all fine an dandy, and it works perfect, but what if I want to go a bit further. So I create another function that can use showRecord to print out all of the names in the address book that have been stored to my file. I tried this:
void addressBook::showAll() {
ifstream indata("vectortest.dat", ios::binary);
for(int i = 0; i < indata.end; i++) {
showRecord(i);
}
}
and it works, but it only prints out the stuff that's hard coded into my PERSON struct from a previous assignment:
addressBook *newBook = addressBook::newbookInst();
PERSON me[] = {{"First" , "Last", "ADDRESS"}, {"John", "Doe", "1234"}};
newBook->addPerson(me[1]);
newBook->addPerson(me[0]);
which is just odd beacuse when I go into the file itself, I can see all of the names that were added.
So how do I use this so that it actually prints out everything in the file, and not just the two entries that are permanently stored?
Here is my addressbook.h and addressbook.cpp code in case you need a better understanding of whats going on...
\\addressbook.h////////
#ifndef _ADDRESSBOOK
#define _ADDRESSBOOK
#include <fstream>
#include <vector>
#include<string>
using std::string;
#include <iostream>
using namespace std;
using std::istream;
using std::ostream;
namespace CJ
{
const int MAXADDRESS =25;
struct PERSON
{
string fName;
string lName;
string Address;
};
struct PEOPLE2
{
char fName2[25];
char lName2[25];
char Address2[25];
};
class addressBook
{
private:
vector<PERSON> people;
int head;
int tail;
public:
addressBook();
addressBook(const PERSON &p);
addressBook(const PERSON p[], int size);
addressBook(char *fName, char *lName, char *address);
bool addPerson(const PERSON &p);
bool sortcomp(const PERSON& p1, const PERSON& p2);
bool getPerson(PERSON &p);
bool findPerson(const string& lastName, PERSON& p);
bool findPerson(const string& lastName, const string& firstName, PERSON& p);
void bubbleSort(int *array,int length);
void printBook();
void sort();
void waitKey();
static addressBook *newbookInst();
static addressBook *tempNew;
static PERSON *p();
static PERSON *temPerson;
void showRecord(int pickNum);
void writeRecord();
void showAll();
friend ostream &operator << (ostream &, addressBook &);
addressBook operator =(const string& str);
addressBook &operator +=(const PERSON &p);
addressBook operator [](int x);
};
}
#endif
\\addressbook.cpp/////
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <conio.h>
#include <string>
using std::string;
#include "addressBook.h"
#include "menu.h"
namespace CJ
{
addressBook::addressBook()
: head(0), tail(-1)
{
}
addressBook::addressBook(const PERSON &p)
: head(0), tail(-1)
{
addPerson(p);
}
addressBook::addressBook(const PERSON p[], int size)
: head(0), tail(-1)
{
for(int i = 0; i < size; i++)
addPerson(p[i]);
}
addressBook::addressBook(char *fName, char *lName, char *Address)
: head(0), tail(-1)
{
PERSON tmp;
tmp.fName = fName;
tmp.lName = lName;
tmp.Address = Address;
addPerson(tmp);
}
bool addressBook::addPerson(const PERSON &p)
{
people.push_back(p);
if(tail == -1)
tail++;
return true;
}
bool addressBook::getPerson(PERSON &p)
{
if(tail >=0)
{
if(tail >= people.size())
tail = 0;
p = people[tail];
tail++;
return true;
}
return false;
}
bool addressBook::findPerson(const string &lastName, PERSON &p)
{
for(size_t i = 0; i < people.size(); i++)
{
if(people[i].lName == lastName)
{
PERSON *p = addressBook::p();
*p = people[i];
return true;
}
}
return false;
}
bool addressBook::findPerson(const string &lastName, const string &firstName, PERSON &p)
{
for(size_t i = 0; i < people.size(); i++)
{
if(people[i].lName == lastName && people[i].fName == firstName)
{
PERSON *p = addressBook::p();
*p = people[i];
return true;
}
}
return false;
}
void addressBook::printBook()
{
for(size_t i = 0; i < people.size(); i++)
{
std::cout << people[i].fName << "\t" << people[i].lName << "\t" << people[i].Address << std::endl;
}
}
bool addressBook::sortcomp(const PERSON& p1, const PERSON& p2)
{
int result = (p1.lName.compare(p2.lName)) ;
if ( result > 0 )
return true ;
if ( result < 0 )
return false ;
return (p1.fName.compare(p2.fName)) > 0 ;
}
void addressBook::sort()
{
bool didSwap ;
do
{
didSwap = false ;
for ( unsigned i=1; i<people.size(); ++i )
if ( sortcomp(people[i-1], people[i]) )
{
std::swap(people[i-1], people[i]) ;
didSwap = true ;
}
} while ( didSwap ) ;
}
addressBook &addressBook::operator +=(const PERSON &p)
{
addPerson(p);
return *this;
};
addressBook addressBook::operator [](int x)
{
return people[x];
};
ostream &operator << (ostream &output, addressBook &ab)
{
PERSON tmp;
ab.getPerson(tmp);
output << tmp.fName << " " << tmp.lName << " " << tmp.Address << endl;
return output;
}
addressBook * addressBook::tempNew = NULL;
addressBook *addressBook::newbookInst()
{
if(tempNew == NULL)
{
tempNew = new addressBook;
}
return tempNew;
}
PERSON * addressBook::temPerson = NULL;
PERSON *addressBook::p()
{
if(temPerson == NULL)
{
temPerson = new PERSON;
}
return temPerson;
}
bool status;
char lName[50];
char fName[50];
void addressBook::writeRecord()
{
PEOPLE2 temp;
ofstream outFile("vectortest.dat", ios::app);
if(!outFile)
{
cout << "Error opening file for writing " << endl;
return;
}
for (vector<PERSON>::iterator iter = people.begin(), end = people.end(); iter != end; ++iter)
{
strncpy(temp.fName2, iter->fName.c_str(), 25);
strncpy(temp.lName2, iter->lName.c_str(), 25);
strncpy(temp.Address2, iter->Address.c_str(), 25);
outFile.write(reinterpret_cast<const char *>(&temp), sizeof(PEOPLE2));
}
outFile.close();
}
void addressBook::showRecord(int pickNum)
{
PEOPLE2 p;
ifstream indata("vectortest.dat", ios::binary);
if(!indata)
{
cout << "Error opening file for reading " << endl;
exit(0);
}
indata.seekg(pickNum * sizeof(PEOPLE2));
indata.read(reinterpret_cast<char *>(&p), sizeof(PEOPLE2));
cout << p.fName2 << " " << p.lName2 << " " << p.Address2 << " " << endl;
indata.close();
}
void addressBook::showAll()
{
ifstream indata("vectortest.dat", ios::binary);
for(int i = 0; i < indata.end; i ++)
{
showRecord(i);
}
}
}
I don't really know that much about the context of how you're planning to use your address book class. But what I've done is re-work the basic structure of what you had into a little more idiomatic C++. This should hopefully help guide your future work on this class. The reading from file issue that you were having issues with is fixed.
#include <iostream>
#include <iterator>
#include <fstream>
#include <cstdlib>
#include <conio.h>
#include <string>
#include <vector>
#include <algorithm>
const int MAXADDRESS = 25;
struct PEOPLE2
{
char fName2[25];
char lName2[25];
char Address2[25];
};
struct PERSON
{
PERSON()
{}
PERSON(PEOPLE2 p)
: fName(p.fName2), lName(p.lName2), Address(p.Address2)
{}
PERSON(const std::string& first, const std::string& last, const std::string& add)
: fName(first), lName(last), Address(add)
{}
std::string fName;
std::string lName;
std::string Address;
};
// required for std::sort
bool operator< (const PERSON &lhs, const PERSON &rhs)
{
int result = (lhs.lName.compare(rhs.lName));
if(result == 0)
return lhs.fName < rhs.fName;
return result < 0;
}
// required for os << people
std::ostream& operator<< (std::ostream& os, const PERSON& rhs)
{
os << rhs.fName << " " << rhs.lName << " " << rhs.Address;
return os;
}
class addressBook
{
private:
std::vector<PERSON> people;
public:
addressBook()
{ }
addressBook(const PERSON &p)
{
addPerson(p);
}
template<typename IT>
addressBook(IT begin, IT end)
{
std::copy(begin, end, std::back_inserter(people));
}
addressBook(char *fName, char *lName, char *address)
{
PERSON tmp;
tmp.fName = fName;
tmp.lName = lName;
tmp.Address = address;
addPerson(tmp);
}
addressBook(const std::string& fileName)
{
std::ifstream indata(fileName, std::ios::binary);
PEOPLE2 p;
while(true)
{
indata.read(reinterpret_cast<char*>(&p), sizeof(PEOPLE2));
if(indata.fail())
break;
people.push_back(p);
}
}
void addPerson(const PERSON &p)
{
people.push_back(p);
}
bool findPerson(const std::string& lastName, PERSON& p)
{
std::find_if(std::begin(people), std::end(people), [&](const PERSON& in)->bool
{
if(lastName == in.lName)
{
p = in;
return true;
}
return false;
});
}
bool findPerson(const std::string& lastName, const std::string& firstName, PERSON& p)
{
std::find_if(std::begin(people), std::end(people), [&](const PERSON& in)->bool
{
if(lastName == in.lName && firstName == in.fName)
{
p = in;
return true;
}
return false;
});
}
void printBook()
{
std::for_each(std::begin(people), std::end(people), [](const PERSON& p)
{
std::cout << p.fName << "\t" << p.lName << "\t" << p.Address << std::endl;
});
}
void sort()
{
std::sort(std::begin(people),std::end(people));
}
void waitKey();
void showRecord(int pickNum)
{
std::cout << people[pickNum] << std::endl;
}
void writeRecord(const std::string& fileName)
{
PEOPLE2 temp;
std::ofstream outFile(fileName, std::ios::app);
if(!outFile)
{
std::cout << "Error opening file for writing " << std::endl;
return;
}
for(auto iter = people.begin(), end = people.end(); iter != end; ++iter)
{
strncpy(temp.fName2, iter->fName.c_str(), 25);
strncpy(temp.lName2, iter->lName.c_str(), 25);
strncpy(temp.Address2, iter->Address.c_str(), 25);
outFile.write(reinterpret_cast<const char *>(&temp), sizeof(PEOPLE2));
}
}
void showAll()
{
std::for_each(std::begin(people), std::end(people), [](const PERSON& in)
{
std::cout << in << std::endl;
});
}
friend std::ostream &operator << (std::ostream &output, addressBook &ab)
{
std::for_each(std::begin(ab.people), std::end(ab.people), [&](const PERSON& in)
{
output << in << "\n";
});
return output;
}
addressBook &operator +=(const PERSON &p)
{
addPerson(p);
return *this;
};
PERSON operator [](int x)
{
return people[x];
};
};
std::string fileName = "c:\\temp\\test.rec";
int main()
{
addressBook ab(fileName);
ab.sort();
ab.showAll();
//addressBook ab;
//ab.addPerson(PERSON("Mary", "Smith", "1 West Street"));
//ab.addPerson(PERSON("Joe", "Brown", "2 East Street"));
//ab.addPerson(PERSON("Harry", "Cooper", "3 South Street"));
//ab.writeRecord(fileName);
}