I'm learning new operator and I have the next question:
I want to reserve new memory when I add a new subject and if I do this way I lose all the previus content of array.
So, how can I do this if i have to reserve memory each time that i want to add a new subject? Or in other words, how i reserve memory without lose the previus?
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <string>
using namespace std;
class Subject {
public:
Subject() { m_name = "";
m_hours = 0;
}
string getName() { return m_name; }
int getHours() { return m_hours; }
void setName(string name) { m_name = name; }
void setHours(int hours) { m_hours = hours; }
private:
string m_name;
int m_hours;
};
class Person {
private:
string m_name;
int m_age;
Subject *m_subjects;
int m_nSubjects;
public:
Person() {
m_name = "";
m_age = 0;
m_nSubjects = 0;
}
~Person() {
}
string getName() { return m_name; }
int getAge() { return m_age; }
void setName(string name) {
m_name = name;
}
void setAge(int age) {
m_age = age;
}
void addSubject(string name, int hour);
void showSubjects();
};
void Person::addSubject(string name, int hours) {
m_subjects = new Subject[m_nSubjects+1]; *the problem is here, all the previus content is lost*
m_subjects[m_nSubjects].setName(name);
m_subjects[m_nSubjects].setHours(hours);
m_nSubjects++;
}
void Person::showSubjects() {
for (int i = 0; i < m_nSubjects; i++) {
cout << m_subjects[i].getName();
cout << "\n";
cout << m_subjects[i].getHours();
}
}
int main() {
int nSubjects;
string name;
int hours;
Person person1;
person1.setName("Name 1");
person1.setAge(30);
cout << "Subjects to add: ";
cin >> nSubjects;
for (int i = 0; i < nSubjects; i++) {
cout << "Name of subject: " << "\n" << endl;
cin >> name;
cout << "Hours: " << "\n" << endl;
cin >> hours;
person1.addSubject(name, hours);
}
person1.showSubjects();
system("pause");
return 0;
}
I hope you can understand me.
You need to copy the existing data to the new array before you then replace the previous array (which you are leaking, BTW), eg:
void Person::addSubject(string name, int hours) {
Subject *new_subjects = new Subject[m_nSubjects+1];
for(int i = 0; i < m_nSubjects; ++i) {
new_subjects[i] = m_subjects[i];
}
new_subjects[m_nSubjects].setName(name);
new_subjects[m_nSubjects].setHours(hours);
delete[] m_subjects;
m_subjects = new_subjects;
m_nSubjects++;
}
You also need to free the current array in your Person destructor to avoid leaking as well:
~Person() {
delete[] m_subjects;
}
And you also need to add a copy constructor and a copy assignment operator to Person as well, to avoid future problems with multiple Person objects sharing the same array in memory if you assign one Person to another:
Person(const Person &src) {
m_name = src.m_name;
m_age = src.m_age;
m_nSubjects = src.m_nSubjects;
m_subjects = new Subject[m_nSubjects];
for (int i = 0; i < m_nSubjects; ++i) {
m_subjects[i] = src.m_subjects[i];
}
}
Person& operator=(const Person &rhs) {
if (&rhs != this) {
Person copy(rhs);
std::swap(m_name, copy.m_name);
std::swap(m_age, copy.m_age);
std::swap(m_nSubjects, copy.m_nSubjects);
std::swap(m_subjects, copy.m_subjects);
}
return *this;
}
And, if you are using C++11 or later, you should (optionally) also add a move constructor and move assignment operator to Person, too:
Person(Person &&src) {
m_name = std::move(src.m_name);
m_age = src.m_age; src.m_age = 0;
m_nSubjects = src.m_nSubjects; src.m_nSubjects = 0;
m_subjects = src.m_subjects; src.m_subjects = nullptr;
}
Person& operator=(Person &&rhs) {
Person movedTo(std::move(rhs));
std::swap(m_name, movedTo.m_name);
std::swap(m_age, movedTo.m_age);
std::swap(m_nSubjects, movedTo.m_nSubjects);
std::swap(m_subjects, movedTo.m_subjects);
return *this;
}
See the Rule of 3/5/0 for more details.
A better solution is to use std::vector instead, let the compiler handle all of these details for you:
#include <iostream>
#include <string>
#include <vector>
#include <limits>
class Subject {
public:
Subject() {
m_name = "";
m_hours = 0;
}
Subject(std::string name, int hours) {
m_name = name;
m_hours = hours;
}
std::string getName() const { return m_name; }
int getHours() const { return m_hours; }
void setName(std::string name) { m_name = name; }
void setHours(int hours) { m_hours = hours; }
private:
std::string m_name;
int m_hours;
};
class Person {
private:
std::string m_name;
int m_age;
std::vector<Subject> m_subjects;
public:
Person() {
m_name = "";
m_age = 0;
}
std::string getName() const { return m_name; }
int getAge() const { return m_age; }
void setName(std::string name) { m_name = name; }
void setAge(int age) { m_age = age; }
void addSubject(std::string name, int hour);
void showSubjects() const;
};
void Person::addSubject(string name, int hours) {
m_subjects.push_back(Subject(name, hours));
}
void Person::showSubjects() const {
for (std::size_t i = 0; i < m_nSubjects.size(); ++i) {
cout << m_subjects[i].getName();
cout << "\n";
cout << m_subjects[i].getHours();
}
}
int main() {
int nSubjects;
std::string name;
int hours;
Person person1;
person1.setName("Name 1");
person1.setAge(30);
std::cout << "Subjects to add: ";
std::cin >> nSubjects;
for (int i = 0; i < nSubjects; i++) {
std::cout << "Name of subject: ";
std::getline(std::cin, name);
std::cout << "Hours: ;
std::cin >> hours;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
person1.addSubject(name, hours);
}
person1.showSubjects();
std::system("pause");
return 0;
}
Related
I have a base class Participant and I need to sort object in array of participant by quantity of their prizes or diplomas. The virtual function get_data return this number. But whileI try to sort, i've got error Access violation executing in row with comparing 2 numbers.
if (p[j].Get_Data() < p[i].Get_Data()) {
This is my full code:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Participant {
protected:
string name;
string surname;
vector <string> type;
int age;
public:
Participant() : name(""), surname(""), type(), age(0)
{}
Participant(string name, string surname, vector <string> type, int age) {
this->name = name;
this->surname = surname;
this->type = type;
this->age = age;
};
Participant(const Participant& other) : name(other.name), surname(other.surname), type(other.type), age(other.age)
{
}
Participant& operator=(const Participant& other)
{
name = other.name;
surname = other.surname;
type = other.type;
age = other.age;
return *this;
}
virtual int Get_Data() {
return 0;
}
friend void Sort(Participant* p);
};
class Diploma : public Participant {
protected:
vector<int> places;
vector <string> type_d;
public:
Diploma() : places(), type_d{}
{}
Diploma(string name, string surname, vector <string> type, int age, vector<int> places, vector <string> type_d);
int Get_Data() override {
cout << "diplom prize" << endl;
cout << type_d.size() << endl;
return type_d.size();
}
};
class Prize : public Participant {
protected:
vector <int> places;
vector<string> prize;
public:
Prize(string name, string surname, vector <string> type, int age, vector<int> places, vector<string> prize);
int Get_Data() override{
cout << "Cont prize" << endl;
cout << prize.size() << endl;
return prize.size();
}
};
Prize::Prize(string name, string surname, vector <string> type, int age, vector<int> places, vector<string> prize) {
this->name = name;
this->surname = surname;
this->type = type;
this->age = age;
this->places = places;
this->prize = prize;
}
Diploma::Diploma(string name, string surname, vector <string> type, int age, vector<int> places, vector <string> type_d){
this->name = name;
this->surname = surname;
this->type = type;
this->age = age;
this->places = places;
this->type_d = type_d;
}
void Sort(Participant* p) {
Participant temp;
for (int i = 0; i < 3; i++) {
for (int j = i + 1; j < 3; j++)
{
if (p[j].Get_Data() < p[i].Get_Data()) {
temp = p[i];
p[i] = p[j];
p[j] = temp;
}
}
}
}
int main() {
Participant* pa[3];
pa[0] = new Diploma("Alex", "Smith", { "Geo","Math" }, 17, { 1,6 }, { "first"});
pa[1] = new Prize("Helen", "Blink", { "IT","Math" }, 18, { 2,2 }, {"Golden medal", "medal"});
pa[2] = new Prize("Brandon", "Brown", { "IT","Math" }, 18, { 2,2 }, { "Golden medal", "medal","gold"});
Sort(*pa);
for (int i = 0; i < 3; i++) {
pa[i]->Get_Data();
cout << endl;
}
}
The issue here is that when you are passing *pa, only the first element is accessible. If you run it in debug mode you will be able to see that inside sort function, p[1] is not a valid object. Basically, only p[0] is passed to the function. You should pass the reference to the array i.e. **pa to the sort function
void Sort(Participant **p)
{
Participant *temp;
for (int i = 0; i < 3; i++)
{
for (int j = i + 1; j < 3; j++)
{
if (p[j]->Get_Data() < p[i]->Get_Data())
{
temp = p[i];
p[i] = p[j];
p[j] = temp;
}
}
}
}
int main()
{
Participant *pa[3];
pa[0] = new Diploma("Alex", "Smith", {"Geo", "Math"}, 17, {1, 6}, {"first"});
pa[1] = new Prize("Helen", "Blink", {"IT", "Math"}, 18, {2, 2}, {"Golden medal", "medal"});
pa[2] = new Prize("Brandon", "Brown", {"IT", "Math"}, 18, {2, 2}, {"Golden medal", "medal", "gold"});
Sort(pa);
for (int i = 0; i < 3; i++)
{
pa[i]->Get_Data();
cout << endl;
}
}
I am working on a school project that is all about pointers. I have been setting variables that string just fine but when I arrived at an int it throws
Exception thrown: read access violation. this was 0xFFFFFFFFFFFFFF5F
I am not sure what this particular variable age is a problem and the rest were fine.
I tried to set int age = 0; to initialize it somehow but no success. Here is the screenshot and the files if that helps narrow down the issue.
Student.cpp
#pragma once
#include <string>
#include <iostream>
#include "student.h"
#include "degree.h"
using namespace std;
// Accessors
string Student::getStudent_ID()
{
return Student_ID;
}
string Student::getFirst_Name()
{
return First_Name;
}
string Student::getLast_Name()
{
return Last_Name;
}
string Student::getEmail_Address()
{
return Email_Address;
}
int Student::getAge()
{
return age;
}
int* Student::getNumber_Days()
{
return Number_Days;
}
DegreeProgram Student::getDegreeProgram()
{
return degreeProgram;
}
//Mutators
void Student::setStudent_ID(string student_ID)
{
this->Student_ID = Student_ID;
}
void Student::setFirst_Name(string first_Name)
{
this->First_Name = First_Name;
}
void Student::setLast_Name(string last_Name)
{
this->Last_Name = Last_Name;
}
void Student::setEmail_Address(string email_Address)
{
this->Email_Address = Email_Address;
}
void Student::setAge(int age)
{
this->age = age;
}
void Student::setNumber_Days(int* Number_Days)
{
this->Number_Days[0] = Number_Days[0];
this->Number_Days[1] = Number_Days[1];
this->Number_Days[2] = Number_Days[2];
}
void Student::setDegreeProgram(DegreeProgram degreeProgram)
{
this->degreeProgram = degreeProgram;
}
//Constructor - essentually the same as a group of setters
Student::Student(string Student_ID, string First_Name, string Last_Name, string Email_Address, int age, int Number_Days[], DegreeProgram degreeProgram)
{
this->Student_ID = Student_ID;
this->First_Name = First_Name;
this->Last_Name = Last_Name;
this->Email_Address = Email_Address;
this->age = age;
this->Number_Days[0] = Number_Days[0];
this->Number_Days[1] = Number_Days[1];
this->Number_Days[2] = Number_Days[2];
this->degreeProgram = degreeProgram;
}
void Student::print()
{
cout << Student_ID << "\t" << First_Name << "\t" << Last_Name << "\t" << age << "\t" << Number_Days[0] << "\t" << Number_Days[1] << "\t" << Number_Days[2] << "\t" << degreeProgram << endl;
}
the Student.h file
#pragma once
#include <string>
#include <iostream>
#include "degree.h"
using namespace std;
class Student
{
private:
string Student_ID;
string First_Name;
string Last_Name;
string Email_Address;
int age;
int* Number_Days = 0;
DegreeProgram degreeProgram;
public:
//initialize need help
// accessors
Student(string Student_ID, string First_Name, string Last_Name, string Email_Address, int age, int Number_Days[], DegreeProgram degreeProgram);
string getStudent_ID();
string getFirst_Name();
string getLast_Name();
string getEmail_Address();
int getAge();
int* getNumber_Days();
DegreeProgram getDegreeProgram();
// mutators
void setStudent_ID(string);
void setFirst_Name(string);
void setLast_Name(string);
void setEmail_Address(string);
void setAge(int);
void setNumber_Days(int Number_Days[]);
void setDegreeProgram(DegreeProgram degreeProgram);
void print();
~Student();
};
Roster.cpp
#pragma once
#include <string>
#include <iostream>
#include <stdlib.h>
#include "student.h"
#include "degree.h"
#include "roster.h"
using namespace std;
//Student* classRosterArray[5];
//void add(string Student_ID, string First_Name, string Last_Name, string Email_Address, int Age, int Number_Days[], DegreeProgram degreeProgram);
//Student* classRosterArray[5]; //string studentData() = 0;
const string studentData[] =
{ "A1,John,Smith,John1989#gm ail.com,20,30,35,40,SECURITY",
"A2,Suzan,Erickson,Erickson_1990#gmailcom,19,50,30,40,NETWORK",
"A3,Jack,Napoli,The_lawyer99yahoo.com,19,20,40,33,SOFTWARE",
"A4,Erin,Black,Erin.black#comcast.net,22,50,58,40,SECURITY",
"A5,Rebekah,Johnson,rjoh804#wgu.edu,27,35,56,65,SOFTWARE" };
//2.E Looping through StudentData and parsing it
//Student* classRosterArray[];
void Roster::add(string Student_ID, string First_Name, string Last_Name, string Email_Address, int age, int Number_Days1, int Number_Days2, int Number_Days3, DegreeProgram degreeProgram)
//void Roster::parsingStudentData()
{
for (int i = 0; i < 5; i++)
{
//string studentData[];
int rhs = studentData[i].find(",");
classRosterArray[i]->setStudent_ID(studentData[i].substr(0, rhs));
int lhs = rhs + 1;
rhs = studentData[i].find(",", lhs);
classRosterArray[i]->setFirst_Name(studentData[i].substr(lhs, rhs - lhs));
lhs = rhs + 1;
rhs = studentData[i].find(",", lhs);
classRosterArray[i]->setLast_Name(studentData[i].substr(lhs, rhs - lhs));
lhs = rhs + 1;
rhs = studentData[i].find(",", lhs);
classRosterArray[i]->setEmail_Address(studentData[i].substr(lhs, rhs - lhs));
lhs = rhs + 1;
rhs = studentData[i].find(",", lhs);
classRosterArray[i]->setAge(stoi(studentData[i].substr(lhs, rhs - lhs))); // Made the string an int with "stoi"// help
//int NumberDays[Student::Number_Days];
lhs = rhs + 1;
rhs = studentData[i].find(",", lhs);
int NumberDays1 = stoi(studentData[i].substr(lhs, rhs - lhs));
lhs = rhs + 1;
rhs = studentData[i].find(",", lhs);
int NumberDays2 = stoi(studentData[i].substr(lhs, rhs - lhs));
lhs = rhs + 1;
rhs = studentData[i].find(",", lhs);
int NumberDays3 = stoi(studentData[i].substr(lhs, rhs - lhs));
int NumberDays[3] = { NumberDays1, NumberDays2, NumberDays3 };
classRosterArray[i]->setNumber_Days(NumberDays);
//Enum type
lhs = rhs + 1;
rhs = studentData[i].find(",", lhs);
//TO FINISH, THIS NEEDs TO BE REFINED, WE do not have the word in between defined"studentData[i].substr(lhs, rhs - lhs)" done
if (studentData[i] == "SECURITY")
classRosterArray[i]->setDegreeProgram(SECURITY);
else if (studentData[i] == "SOFTWARE")
classRosterArray[i]->setDegreeProgram(SOFTWARE);
else
classRosterArray[i]->setDegreeProgram(NETWORK);
}
//void Roster::add();
}
void Roster::remove(string Student_ID)
{
for (int i = 0; i < 5; i = i + 1)
{
if (Student_ID == classRosterArray[i]->getStudent_ID())
{
classRosterArray[i] = nullptr;
}
else
{
cout << "Error:Student not found" << endl;
}
}
}
void Roster::printAll()
{
for (int i = 0; i < 5; i = i + 1)
{
this->classRosterArray[i]->print();
//cout << Student_ID << /t << First_Name << /t << Last_Name << /t << Age << /t << Number_Days[] <<
}
}
void Roster::printAverageDaysInCourse(string Student_ID)
{
for (int i = 0; i < 5; i = i + 1)
{
//this->classRosterArray[i]->getNumber_Days();
//int* Number_Days[] = classRosterArray[i]->getNumber_Days();
int AvgDays = (classRosterArray[i]->getNumber_Days()[0] + classRosterArray[i]->getNumber_Days()[1] + classRosterArray[i]->getNumber_Days()[2]) / 3;
cout << Student_ID << ": " << AvgDays << endl;
}
}
void Roster::printInvalidEmails()
{
for (int i = 0; i < 5; i = i + 1)
{
string Email_Check = classRosterArray[i]->getEmail_Address();
string StudentID = classRosterArray[i]->getStudent_ID();
if (Email_Check.find("#") == string::npos or Email_Check.find(".") == string::npos or Email_Check.find(" ") != string::npos)
{
cout << StudentID << ": Invalid Email" << endl;
}
}
}
void Roster::printByDegreeProgram(DegreeProgram degreeProgram)
{
for (int i = 0; i < 5; i = i + 1)
{
if (classRosterArray[i]->getDegreeProgram() == degreeProgram)
{
classRosterArray[i]->print();
}
}
}
Roster.h
#pragma once
#include <string>
#include <iostream>
#include "student.h"
#include "degree.h"
using namespace std;
class Roster
{
Student* classRosterArray[5]; // = { 0,0,0 }; // Array holding Student data table information
void inicializeArray()
{
classRosterArray[0] = 0; // elements of the array initialized to 0
classRosterArray[1] = 0;
classRosterArray[2] = 0;
classRosterArray[3] = 0;
classRosterArray[4] = 0;
}
void parsingStudentData();
//classRosterArray=(Student1, Student2, )
// classRosterArray[2] = 37; // sets Student3 to 37 // to access the variables in classRosterArray
//Roster* classRosterArray[] = { "Student_ID", "First_Name", "Last_Name", "Email_Address", " Age", " Number_Days[]", "DegreeProgram"};
public:
void add(string Student_ID, string First_Name, string Last_Name, string Email_Address, int Age, int Number_Days1, int Number_Days2, int Number_Days3, DegreeProgram degreeProgram);
void remove(string Student_ID);
void printAll();
void printAverageDaysInCourse(string Student_ID);
void printInvalidEmails();
void printByDegreeProgram(DegreeProgram degreeProgram);
};
Quite new to programming and in need of some help, I'm looking to sort an class array in ascending order based on age, but I can only get the code to work in descending order. I may be overlooking something small since I've worked on this far too long so I'd appreciate any help!
#include <iostream>
#include <string>
using namespace std;
class Person
{
public:
string name;
int age;
Person(string name = "empty", int age = 0)
{
setName(name);
setAge(age);
}
void setName(string x) {
name = x;
}
string getName() {
return name;
}
void setAge(int y) {
age = y;
}
int getAge() {
return age;
}
void displayinfo()
{
cout << "Name: " << name; cout << " Age: " << age << endl;
}
};
void swap(Person &p, Person &q)
{
Person temp;
temp.name = p.name;
temp.age = p.age;
p.name = q.name;
p.age = q.age;
q.name = temp.name;
q.age = temp.age;
}
int main()
{
int userValue;
Person po("Jessica", 24);
Person po2("Robert", 49);
Person po3("Maria", 47);
Person po4("John", 19);
Person family[4] = {po,po2,po3,po4};
int sort(family[4].getAge());
{
for(int i = 0; i < 3; i++)
if (family[i].getAge() < family[i+1].getAge())
{
swap(family[i], family[i+1]);
}
}
for(int i = 0; i < 4; i++)
family[i].displayinfo();
}
int sort(family[4].getAge()); is not a function declaration (and you can't implement a function inside of another function). It is actually a variable declaration. It is declaring a variable int sort that is initialized with the value from family[4].getAge() (which is undefined behavior since index 4 is out of bounds of your family[] array).
So, you are declaring an unused sort variable, and then you enter your for(int i = 0; i < 3; i++) loop, which DOES NOT perform a full sort of the array. For what you are attempting, use the standard std::sort() algorithm instead, eg:
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
class Person
{
public:
string name;
int age;
Person(string name = "empty", int age = 0)
{
setName(name);
setAge(age);
}
void setName(string x) {
name = x;
}
string getName() const {
return name;
}
void setAge(int y) {
age = y;
}
int getAge() const {
return age;
}
void displayinfo() const
{
cout << "Name: " << name; cout << " Age: " << age << endl;
}
};
int main()
{
Person po1("Jessica", 24);
Person po2("Robert", 49);
Person po3("Maria", 47);
Person po4("John", 19);
Person family[4] = {po1, po2, po3, po4};
std::sort(family, family + 4,
[](const Person &p1, const Person &p2) {
return p1.getAge() < p2.getAge();
}
);
for(int i = 0; i < 4; i++) {
family[i].displayinfo();
}
return 0;
}
Live Demo
Note that your family[] array holds copies of the Person objects that you initialize it with. To avoid the overhead of those copies, you can sort pointers instead, eg:
int main()
{
Person po1("Jessica", 24);
Person po2("Robert", 49);
Person po3("Maria", 47);
Person po4("John", 19);
Person* family[4] = {&po1, &po2, &po3, &po4};
std::sort(family, family + 4,
[](const Person *p1, const Person *p2) {
return p1->getAge() < p2->getAge();
}
);
for(int i = 0; i < 4; i++) {
family[i]->displayinfo();
}
return 0;
}
Live Demo
Or, you can get rid of the individual p0... objects altogether and initialize the array directly instead, eg:
int main()
{
Person family[4]{
{"Jessica", 24},
{"Robert", 49},
{"Maria", 47},
{"John", 19}
};
std::sort(family, family + 4,
[](const Person &p1, const Person &p2) {
return p1.getAge() < p2.getAge();
}
);
for(int i = 0; i < 4; i++) {
family[i].displayinfo();
}
return 0;
}
Live Demo
I'm working on a project to handle an inventory of cars. There is a base Vehicle class and a derived AdvancedVehicle class. I am running into an issue with my serialize function which is meant to be a virtual function. It seems that whenever the function is called by either the base or derived class, it only runs the base serialize function. Attached is both the Vehicle and AdvancedVehicle class definitions and implementations.
/////////////////////////////// VEHICLE //////////////////////////////////
class Vehicle{
friend ostream& operator<< (ostream& os, const Vehicle v) {
v.Serialize(os);
return os;
}
public:
Vehicle() = delete;
Vehicle(string model, size_t year, float price) {
m_model = model;
m_year = year;
m_baseprice = price;
m_owner = NULL;
}
Vehicle(string model, size_t year, float price, const Client* owner) {
m_model = model;
m_year = year;
m_baseprice = price;
m_owner = new Client("");
*m_owner = *owner;
}
Vehicle(const Vehicle& otherVehicle) {
m_model = otherVehicle.m_model;
m_year = otherVehicle.m_year;
m_baseprice = otherVehicle.m_baseprice;
m_owner = NULL;
}
Vehicle& operator= (const Vehicle& otherVehicle) {
m_model = otherVehicle.m_model;
m_year = otherVehicle.m_year;
m_baseprice = otherVehicle.m_baseprice;
m_owner = new Client("");
*m_owner = *otherVehicle.m_owner;
return *this;
}
void setPrice(float price) {
m_baseprice = price;
}
void SetOwner(const Client* owner) {
m_owner = new Client("");
if(owner)
{
*m_owner = *owner;
}
}
string GetModel() const { return m_model; }
size_t GetYear() const { return m_year; }
virtual float GetPrice() const { return m_baseprice; }
Client* GetOwner() const { return m_owner; }
virtual void Serialize(ostream& os) const {
os << m_year << " ";
os << m_model << " ";
os << m_baseprice << " ";
if(m_owner != NULL)
{
os << *m_owner << endl;
}
}
protected:
string m_model;
size_t m_year;
private:
float m_baseprice;
Client* m_owner;
};
/////////////////////////// ADVANCEDVEHICLE ///////////////////////////////
class AdvancedVehicle : public Vehicle{
friend ostream& operator<< (ostream& os, const AdvancedVehicle AV) {
AV.Serialize(os);
return os;
}
public:
AdvancedVehicle() = delete;
AdvancedVehicle(string model, size_t year, float price, vector<Sensor> sensors, const Client* owner):Vehicle (model, year, price){
m_model = model;
m_year = year;
SetOwner(owner);
setPrice(price);
for(auto i = sensors.begin(); i != sensors.end(); i++)
{
int j = 0;
AddSensor(sensors[j]);
j++;
}
}
AdvancedVehicle(string model, size_t year, float price, vector<Sensor> sensors):Vehicle (model, year, price){
m_model = model;
m_year = year;
SetOwner(NULL);
setPrice(price);
for(auto i = sensors.begin(); i != sensors.end(); i++)
{
int j = 0;
AddSensor(sensors[j]);
j++;
}
}
AdvancedVehicle(const AdvancedVehicle& otherAV):Vehicle( otherAV) {
m_model = otherAV.m_model;
m_year = otherAV.m_year;
m_finalprice = otherAV.m_finalprice;
SetOwner(NULL);
for(auto i = otherAV.m_sensors.begin(); i != otherAV.m_sensors.end(); i++)
{
int j = 0;
AddSensor(otherAV.m_sensors[j]);
j++;
}
}
AdvancedVehicle& operator=(const AdvancedVehicle& otherAV) {
m_model = otherAV.m_model;
m_year = otherAV.m_year;
setPrice(otherAV.GetPrice());
SetOwner(otherAV.GetOwner());
for(auto i = otherAV.m_sensors.begin(); i != otherAV.m_sensors.end(); i++)
{
int j = 0;
AddSensor(otherAV.m_sensors[j]);
j++;
}
return *this;
}
void AddSensor(Sensor addedSensor) {
m_sensors.push_back(addedSensor);
m_finalprice += addedSensor.GetPrice();
}
virtual float GetPrice() const { return m_finalprice; }
virtual void Serialize(ostream& os) const {
os << m_year << " ";
os << m_model << " ";
os << m_finalprice << " ";
if(GetOwner() != NULL)
{
os << GetOwner() << " ";
}
for(auto i = m_sensors.begin(); i != m_sensors.end(); i++)
{
os << &i << " ";
}
os << endl;
}
private:
vector<Sensor> m_sensors;
float m_finalprice;
};
Your program is suffering from the object slicing problem. The operator<< takes a Vehicle object by value. This means a new Vehicle object is copy-constructed from the argument passed to the operator. The new object is a Vehicle, not an AdvancedVehicle, even if what was passed to the operator was an AdvancedVehicle. The object is said to have been sliced and this is why the base version of the Serialize() function is called.
To address this, you should modify the operator<< overload to take a Vehicle by reference (Vehicle&). This will eliminate the copy and the slicing.
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);
}