c++ trouble with either RTTI or binary file io - c++

I think I am having trouble with binary file io. If I run my program, create some employee objects and then display them everything works fine. If I save the object data and reload the program I get an RTTI exception. It apears to me that my LoadEmployeeData() and Savelist(vector &e) functions work just fine. The exception occurs in my DisplayEmployeeData() function when I try to use typeid.
Just to reiterate, I am getting an RTTI error when using typeid on an object loaded from disk.
//****************header file***********
#include <string.h>
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <sstream>
#include <typeinfo>
#include <ctime>
#include <cstdlib>
using namespace std;
class Employee
{
private:
int employeeID;
char name[80];
int SSN;
public:
Employee();
Employee(int, char*,int);
virtual ~Employee();
virtual void DisplayBaseData();
//getters
int GetID();
char* getName();
int GetSSN();
//setters
void SetID(int);
void SetName(char*);
void SetSSN(int);
};//end Employee class
class Salary : public Employee
{
private:
double salary;
public:
Salary();
Salary(int, char*, int, double); //id, name, ssn, salary
~Salary();
void DisplayEmployeeData();
//getters
double GetSalary();
//setters
void SetSalary(double);
};//end class Exempt
class Hourly : public Employee
{
private:
double rate;
double hoursWorked;
public:
Hourly();
Hourly(int, char*, int, double, double); //id, name, ssn, rate
~Hourly();
void DisplayEmployeeData();
//getters
double GetRate();
double GetHoursWorked();
//setters
void SetRate(double);
void SetHoursWorked(double);
};//end Hourly Class
const int HOURLYTYPE = 0;
const int SALARYTYPE = 1;
//*******body*******
#include "lab05.h";
Employee::Employee(){};
Employee::Employee(int ID, char* nme, int ssn) : employeeID(ID), SSN(ssn)
{
strcpy(name, nme);
}
int Employee::GetID()
{
return employeeID;
}
char* Employee::getName()
{
return name;
}
int Employee::GetSSN()
{
return SSN;
}
void Employee::SetID(int i)
{
employeeID = i;
}
void Employee::SetName(char* n)
{
strcpy(name, n);
}
void Employee::SetSSN(int i)
{
SSN = i;
}
void Employee::DisplayBaseData()
{
cout << "ID: \t" << employeeID << endl;
cout << "Name: \t " << name << endl;
cout << "SSN: \t" << SSN << endl;
}
Employee::~Employee(){}
Salary::Salary(){}
Salary::Salary(int id, char* nme, int ssn, double slry) : Employee(id, nme, ssn), salary(slry){}
void Salary::DisplayEmployeeData()
{
DisplayBaseData();
cout << "Salary: \t " << salary << endl;
}
double Salary::GetSalary()
{
return salary;
}
void Salary::SetSalary(double d)
{
salary = d;
}
Salary::~Salary(){}
Hourly::Hourly(){}
Hourly::Hourly(int id, char* nme, int ssn, double rte, double worked) : Employee(id, nme, ssn), rate(rte), hoursWorked(worked){}
void Hourly::DisplayEmployeeData()
{
DisplayBaseData();
cout << "Rate: \t" << rate << endl;
cout << "Worked: \t " << hoursWorked << endl;
}
double Hourly::GetRate()
{
return rate;
}
double Hourly::GetHoursWorked()
{
return hoursWorked;
}
void Hourly::SetRate(double d)
{
rate = d;
}
void Hourly::SetHoursWorked(double d)
{
hoursWorked = d;
}
Hourly::~Hourly(){}
vector<Employee*> LoadEmployeeData()
{
vector<Employee*> employeeList;
string fileName = "";
cout << "\nEnter filename for employee data: ";
cin >> fileName;
fstream file;
file.open(fileName, ios::in, ios::binary);
char buffer[4096] = {0};
int numEntries;
file.read((char*)&numEntries, sizeof(int));
cout << numEntries << " number of entries found." << endl;
if (numEntries != 0)
{
int identifier;
for (int i = 0; i < numEntries; i++)
{
file.read((char*)&identifier, sizeof(int));
if (identifier == SALARYTYPE)
{
Employee* temp = new Salary();
file.read((char*)temp, sizeof(Salary));
employeeList.push_back(temp);
}
else if (identifier == HOURLYTYPE)
{
Employee* temp = new Hourly();
file.read((char*)temp, sizeof(Hourly));
employeeList.push_back(temp);
}
}
}
else cout << "No Entries found." << endl;
file.close();
return employeeList;
}//end LoadEmployeeData function
void ListEmployees(vector<Employee*> &e)
{
if (e.size() != 0)
{
for (int i = 0; i < e.size(); i++)
{
if (typeid(*(e[i])) == typeid(Hourly))
{
cout << "\n(" << i << ")" << endl;
dynamic_cast<Hourly*>(e[i])->DisplayEmployeeData();
}
else if (typeid(*(e[i])) == typeid(Salary))
{
cout << "\n(" << i << ")" << endl;
dynamic_cast<Salary*>(e[i])->DisplayEmployeeData();
}
}
}
else cout << "No items in list" << endl;
}// end ListEmployees function
void ModifyEmployee(vector<Employee*> &e)
{
cout << "Enter employee selection." << endl;
}
void CreateEmployee(vector<Employee*> &e)
{
bool continueLoop = true;
srand(time(0)); //seed random number generator
cout << "\n Enter new employee information." << endl;
cout << "Name: ";
char newName[80] = {0};
cin >> newName;
cout << "\n SSN: ";
int newSSN;
cin >> newSSN;
char newType = '-1';
do
{
cout << "\n Is new employee paid a (s)alary or (h)ourly rate? ";
cin >> newType;
if (newType == 's' || newType == 'h') continueLoop = false;
else cout << "incorrect input" << endl;
}while (continueLoop == true);
if (newType == 's')
{
cout << "Enter salary amount: ";
double amount;
cin >> amount;
e.push_back(new Salary(rand() % 1000 + 1, newName, newSSN, amount));
}
else if (newType == 'h')
{
cout << "Enter hourly amount: ";
double amount;
cin >> amount;
cout << "Enter hours worked: ";
double hoursWorked;
cin >> hoursWorked;
e.push_back(new Hourly(rand() % 1000 + 1, newName, newSSN, amount, hoursWorked));
}
}
void Savelist(vector<Employee*> &e)
{
if (e.size() == 0)
cout << "No employees in list. Nothing done." << endl;
else
{
cout << "Enter save filename: ";
char fileName[80] = {'\0'};
cin >> fileName;
fstream* file = new fstream();
file->open(fileName, ios::out, ios::binary);
char buffer[80] = {'\0'};
int numEntries = e.size();
file->write((char*)&numEntries, sizeof(int)); //writes number of entries
for (int i = 0; i < e.size(); i++)
{
if (typeid(*e[i]) == typeid(Salary))
{
int classType = SALARYTYPE;
file->write((char*)&classType, sizeof(int));
file->write((char*)dynamic_cast<Salary*>(e[i]), sizeof(Salary));
}
else if (typeid(*e[i]) == typeid(Hourly))
{
int classType = HOURLYTYPE;
file->write((char*)&classType, sizeof(int));
file->write((char*)dynamic_cast<Hourly*>(e[i]), sizeof(Salary));
}
}
file->close();
}
}
void DeleteEmployee(vector<Employee*> &e)
{
cout << "Input index number of employee to delete: ";
int idx = 0;
cin >> idx;
if (idx > e.size() -1)
cout << "invalid index number\n" << endl;
else
{
delete e[idx];
e.erase(e.begin() + idx); //removes from list
}
}
int main()
{
const int ZERO = 0;
const int ONE = 1;
const int TWO = 2;
const int THREE = 3;
const int FOUR = 4;
const int FIVE = 5;
const int SIX = 6;
int exitMainLoop = false; //for flow control
int mainMenuChoice = -1;
vector<Employee*> employeeList;
do
{
cout << "Select from the following options." << endl;
cout << "(1) Load employee data file." << endl;
cout << "(2) View Employees." << endl;
cout << "(3) Modify Employee data. " << endl;
cout << "(4) Create new employee." << endl;
cout << "(5) Save list to file." << endl;
cout << "(6) Delete employee data. " << endl;
cout << "(0) Exit program." << endl;
//add more options
cout << "Enter selection: ";
cin >> mainMenuChoice;
if (cin.fail())
{
cout << "\nInvalid selection. Try again" << endl;
cin.clear();
string garbage = "";
cin >> garbage;
}
else if (mainMenuChoice == ONE)
employeeList = LoadEmployeeData();
else if (mainMenuChoice == TWO)
ListEmployees(employeeList);
else if (mainMenuChoice == THREE)
ModifyEmployee(employeeList);
else if (mainMenuChoice == FOUR)
CreateEmployee(employeeList);
else if (mainMenuChoice == FIVE)
Savelist(employeeList);
else if (mainMenuChoice == SIX)
DeleteEmployee(employeeList);
else if (mainMenuChoice == ZERO)
exitMainLoop = true;
}while(exitMainLoop == false);
system("PAUSE");
}

You can't read/write raw C++ objects from/to disk if they have virtual methods (or use RTTI, which requires virtual methods) because there's no guarantee that the vtable address from the first execution will be written to disk, and there's no guarantee that the vtable will be in the same place the next time the program is run -- hence, the address that was written to disk will point somewhere incorrect when it is read back.

file->write((char*)dynamic_cast<Hourly*>(e[i]), sizeof(Salary));
looks suspicious. did you mean sizeof(Hourly)?

Related

How do I read in a pointer to an object from a file?

I know this program is long, but any help would be much appreciated. When I try to read in an object from a file, I always end up with a segmentation fault. I've commented the line where the problem is. It's under 'case d' in the switch statement.
The objects I'm writing out the text file is polymorphic, which might be part of why I'm getting segmentation faults, but I'm not sure.
#include <iostream>
#include <string.h>
#include <vector>
#include <unistd.h>
#include <fstream>
#include "employee.h"
int main(int argc, char* argv[])
{
std::string command, choice, name;
float wage, percent;
int hours = 1;
std::ofstream file;
std::ifstream infile;
std::vector<Employee*> database;
while (command[0] != 'q')
{
clear();
menu();
std::cout << "Enter command: ";
std::cin >> command;
try
{
if(command.size() != 1)
throw "Not a character.";
else
{
switch(command[0])
{
case 'n':
std::cout << "Enter the name of the new employee: ";
//std::cin >> name;
std::cin.clear();
std::cin.ignore();
getline(std::cin, name);
std::cout << "Hourly (h) or salaried (s): ";
std::cin >> choice;
if(choice.size() != 1)
throw "Not a valid choice.";
else
if(choice == "h")
{
std::cout << "Enter hourly wage: ";
std::cin >> wage;
if(!wage)
throw "Not an option";
else{
Employee *emp = new PartTimeEmployee(wage, name);
database.push_back(emp);
continueWithProgram();
break;
}
}else if(choice == "s")
{
std::cout << "Enter salaried wage: ";
std::cin >> wage;
if(!wage)
throw "Not an option";
else{
Employee *emp = new FullTimeEmployee(wage, name);
database.push_back(emp);
continueWithProgram();
break;
}
}else{
throw "Not an option";
}
case 'c':
if(database.size() < 1)
throw "No employees in database.";
else
{
for(int i = 0; i < database.size(); i++)
{
std::cout << "Enter number of hours worked by " << database[i]->getName() << ": ";
std::cin >> hours;
std::cout << "Pay: $" << database[i]->computePay(hours) << std::endl;
}
continueWithProgram();
}
break;
case 'r':
std::cout << "Enter percentage to increase: ";
std::cin >> percent;
std::cout << "\nNew Wages\n---------" << std::endl;
for(int i = 0; i < database.size(); i++)
{
database[i]->raiseWage(percent);
std::cout << database[i]->getName() << "\t\t" << "$" << database[i]->toString(database[i]->getWage()) << std::endl;
}
continueWithProgram();
break;
case 'p':
std::cout << "\nEmployee Database: " << database[0]->count << " Personnel\n-----------------\n";
for(int i = 0; i < database.size(); i++)
{
std::cout << database[i]->getName() << std::endl;
}
continueWithProgram();
break;
case 'd':
infile.open("emp.txt", std::ios::in);
Employee *temp;
if(infile.is_open())
{
while(!infile.eof())
{
infile >> *temp; // PROBLEM IS HERE...
database.push_back(temp);
}
}else{
std::cout << "Error occured. File not found." << std::endl;
}
infile.close();
std::cout << "*Data has been downloaded*" << std::endl;
continueWithProgram();
break;
case 'u':
file.open("emp.txt", std::ios::trunc);
if(file.is_open()){
for(int i = 0; i < database.size(); i++)
file << *database[i];
}
file.close();
std::cout << "*Data has been uploaded*\n";
continueWithProgram();
break;
default:
if(command[0] == 'q')
break;
else
{
throw "Not a command";
break;
}
}
}
}catch(const char* message)
{
std::cout << message << std::endl;
std::cin.clear();
std::cin.ignore();
continueWithProgram();
}
catch(...)
{
std::cout << "Error occured." << std::endl;
std::cin.clear();
std::cin.ignore();
continueWithProgram();
}
}
return 0;
}
______________________________________________________-
Header File:
*This is where the operator overload is, which I'm sure is not part of the problem.
#include <iostream>
#include <fstream>
#include <string.h>
#include <vector>
#include <unistd.h>
class Employee
{
protected:
float wage;
std::string name;
public:
static int count;
Employee(float wage, std::string name)
{
this->wage = wage;
this->name = name;
count++;
}
virtual float getWage() = 0;
virtual void setWage(float wage) = 0;
virtual float computePay(int hours = 0) = 0;
virtual float raiseWage(float percent = 0) = 0;
virtual std::string toString(int value) = 0;
std::string getName(){return name;}
void setName(std::string name){this->name = name;}
friend std::ofstream& operator<<(std::ofstream &out, Employee &emp);
friend std::ifstream& operator>>(std::ifstream &in, Employee &emp);
};
class FullTimeEmployee : public Employee
{
public:
FullTimeEmployee(float annualSalary, std::string name) : Employee(annualSalary, name)
{
getWage();
}
float getWage() {return wage;}
void setWage(float wage) {this->wage = wage;}
float computePay(int hours = 0) {return (wage / 52);}
std::string toString(int value){return std::to_string(value) + "/year";}
float raiseWage(float percent = 0)
{
wage = wage + (wage * (percent / 100));
return wage;
}
};
class PartTimeEmployee : public Employee
{
public:
PartTimeEmployee(float wage, std::string name) : Employee(wage, name)
{
getWage();
}
float getWage() {return wage;}
void setWage(float wage) {this->wage = wage;}
std::string toString(int value){return std::to_string(value) + "/hour";}
float computePay(int hours)
{
if(hours <= 40)
return wage * hours;
else
{
hours -= 40;
return ((wage * 40) + ((wage * 1.5) * hours));
}
}
float raiseWage(float percent = 0)
{
wage = wage + (wage * (percent / 100));
return wage;
}
};
std::ofstream& operator<<(std::ofstream &out, Employee &emp)
{
out << emp.name << std::endl << emp.wage << std::endl;
return out;
}
std::ifstream& operator>>(std::ifstream &in, Employee &emp)
{
in >> emp.name;
in >> emp.wage;
return in;
}
int Employee::count = 0;
void menu()
{
std::cout << "-----------------------------------" << std::endl;
std::cout << "|Commmands: n - New Employee |" << std::endl;
std::cout << "| c - Compute Paychecks |" << std::endl;
std::cout << "| r - Raise Wages |" << std::endl;
std::cout << "| p - Print Records |" << std::endl;
std::cout << "| d - Download Data |" << std::endl;
std::cout << "| u - Upload Data |" << std::endl;
std::cout << "| q - Quit |" << std::endl;
std::cout << "-----------------------------------" << std::endl;
}
void clear() {std::cout << "\033[2J\033[1;1H";}
int continueWithProgram()
{
std::string anw;
while(anw[0] != 'y' || anw[0] != 'Y')
{
std::cout << "\nDo you want to continue?(y/n) ";
std::cin >> anw;
return 0;
if(anw.size() != 1)
{
throw "Not a character";
}else if (anw[0] == 'n' || anw[0] == 'N')
exit(0);
}
}
You must add subtype information (Ex: 'f' or 'p', denoting partime and fulltime) somewhere in your file-format. If you really want do deserialize a Pointer from the file you might change both operators.
(However I strongly recommend to use an other approach and fix memory leaks):
operator<< should first print an extra line consisting of just one character denoting the subtype of Employ that is serialized.
using PEmployee = *Employee;
std::ifstream& operator>>(std::ifstream &in, PEmployee &emp)
{
char subType;
float wage;
std::string name;
in >> subType;
in >> name; // FIXIT - we suspect file in not eof
in >> wage;
if(subType == 'f')
emp = new FullTimeEmploy(wage, name);
else
emp = new PartTimeEmploy(wage, name); // FIXIT: we suspect subType == 'p'
return in;
}
And in the while-Loop beneath case 'd': you should call the new operator by infile >> temp;
I hope this works and answers your question.
I do not recommend this approach, calling new as side-effect from an operator rises the question who (which part of the Prog) is responsible for cleaning up (i.e. calling delete). It might work in small Progs but usually it will results in a mess.
Memory leaks: If you use new and delete, be always aware where in Your Prog the allocated memory will be freed. It is not done by the Run-time environment, C++ is not a managed language. HINT: std::vector<Employee*> wont call delete on the stored pointers, it just frees its workload (Employee*). It's the pointer itself not the pointee, i.e. the Object you accuired with new .
PS:
A more straight forward aproach is to change only the operator<< and evaluate the subtype inside the while-Loop beneath case 'd': First read the subtype-char, switch subtype, create the according subclass (Ex: temp = new PartTimeEmployee(); and call the unchanged operator>> with the newly created temp.
For this approach you'll need standart Constructors like PartTimeEmployee::PartTimeEmployee(); for all your subclasses.

FOR LOOP fails to iterate through the object vector where purchase transactions are stored

I'm unsure why when more than one transaction has been made the FOR LOOP won't iterate through the vector of "buyers". Am I missing something simple? I've spent the last few hours trying to fix this but to no avail. If any one could possibly help with my problem I'd be eternally grateful.
#include <iostream>
#include <iomanip>
#include <vector>
#include <cctype>
using namespace std;
//This class is for the car details that the user can purchase.
class cCar {
private:
string _sName;
double _dPrice;
public:
cCar(string s, double d)
{
_sName = s;
_dPrice = d;
}
string getName() { return _sName; }
double getPrice() { return _dPrice; }
};
//This is where all the car detail purchases are created and stored in the object 'carlist'
vector<cCar> CarDatabase(vector<cCar>& car_list)
{
car_list.push_back(cCar("Blue Nissan Skyline", 1000));
car_list.push_back(cCar("Red Mini", 3000));
car_list.push_back(cCar("Black Land Rover", 4000));
car_list.push_back(cCar("Beatle", 9000));
car_list.push_back(cCar("Ferrari", 300000));
return car_list;
}
//This class stores the user's transactions
class Finance {
private:
string _sUserName;
double _dCostOfCar;
string _sChosenCar;
int _iFinancePlan;
double _dDepositedAmount;
double _dMonthlyPayments;
double _dTotalLeftToPay;
public:
Finance(string sName, double dCostOfCar, string sChosenCar, int iFinancePlan, double dDepositedAmount, double dDMonthlyPayments, double dTotalLeftToPay)
{
_sUserName = sName;
_dCostOfCar = dCostOfCar;
_sChosenCar = sChosenCar;
_iFinancePlan = iFinancePlan;
_dDepositedAmount = dDepositedAmount;
_dMonthlyPayments = dDMonthlyPayments;
_dTotalLeftToPay = dTotalLeftToPay;
}
string getUserName() { return _sUserName; }
double getdCostOfCar() { return _dCostOfCar; }
string getChosenCar() { return _sChosenCar; }
int getFinancePlan() { return _iFinancePlan; }
double getDepositAmount() { return _dDepositedAmount; }
double getMonthlyAmount() { return _dMonthlyPayments; }
double getTotalLeftToPay() { return _dTotalLeftToPay; }
};
//1. This displays the car menu items.
void display_menu(vector<cCar>& car_list)
{
cout << "\nMENU";
for (int iCount = 0; iCount != car_list.size(); iCount++) {
cout << "\n" << iCount + 1 << ". " << car_list[iCount].getName();
cout << "\n\tPrice: £" << car_list[iCount].getPrice();
cout << "\n";
}
}
//This procedure proccesses the user's selection and all information regarding price and name of car are then transferred to transaction variables.
void selectedCar(vector<cCar>& car_list, string& sNameOfChosenCar, double& dCostOfChosenCar)
{
int iSelectionFromMenu = -1;
do {
cout << "\nChoose a car that you'd wish to buy from the menu (1 - " << car_list.size() << "): ";
cin >> iSelectionFromMenu;
if (iSelectionFromMenu > 0 && iSelectionFromMenu <= car_list.size()) {
sNameOfChosenCar = car_list[iSelectionFromMenu - 1].getName();
dCostOfChosenCar = car_list[iSelectionFromMenu - 1].getPrice();
}
else {
cout << "\nPlease enter valid number!";
iSelectionFromMenu = -1;
}
} while (iSelectionFromMenu == -1);
}
//This procedure gets from the user their preferred finance plan through their input.
void FinanceLength(int& iFinanceLength)
{
do {
cout << "\nHow long do you wish for your finance plan to last? (1 - 4 years): ";
cin >> iFinanceLength;
if (iFinanceLength < 0 || iFinanceLength > 4) {
cout << "\nOops, try again! Please enter between 1 - 4!";
}
} while (iFinanceLength < 0 || iFinanceLength > 4);
}
//This procedure gets the user's deposit.
void DepositMoney(double& dDepositAmount)
{
do {
cout << "\nEnter deposit amount (minimum £500 accepted): £";
cin >> dDepositAmount;
if (dDepositAmount < 500) {
cout << "\nTry again! Deposit an amount greater than or equal to £500.";
}
} while (dDepositAmount < 500);
}
//This function calculates the amount of money the user has to pay after deposit, added tax and charge percentage of 10%
double TotalLeftToPay(double iFinanceLength, double dDepositAmount, double dCostOfChosenCar)
{
double dChargePercentage = 0.10;
double dTotalLeftToPay = dCostOfChosenCar + (dCostOfChosenCar * dChargePercentage) - dDepositAmount + 135;
return dTotalLeftToPay;
}
//This calculates monthly payments.
double MonthlyPayments(double dTotalLeftToPay, int iFinanceLength)
{
double dMonthlyPayments = (dTotalLeftToPay / iFinanceLength) / 12;
return dMonthlyPayments;
}
//This asks the user whether they'd like to restart the application.
void RestartOptions(char& cOption, bool& bExit)
{
do {
cout << "\nDo you wish to make another purchase? (y/n): ";
cin >> cOption;
cOption = toupper(cOption);
switch (cOption) {
case 'Y':
bExit = false;
break;
case 'N':
bExit = true;
break;
default:
cout << "Sorry, that's an invalid input, please try again!";
continue;
}
} while (cOption != 'y' && cOption != 'Y' && cOption != 'n' && cOption != 'N');
}
//This string function returns either year or years (plural)
string YearOrYears(int iFinanceLength)
{
return (iFinanceLength > 1) ? "years" : "year";
}
//This displays receipt of the user's transaction.
//HERE IS WHRERE I "M STRUGGLING TO ITERATE
void Receipt(const string& sUserName, const int& iFinanceLength, const double& dDepositAmount, char cOption, bool& bExit, const string& sNameOfChosenCar, const double& dCostOfChosenCar, vector<Finance>& buyers)
{
double dTotalLeftToPay = TotalLeftToPay(iFinanceLength, dDepositAmount, dCostOfChosenCar);
double dMonthlyPayments = MonthlyPayments(dTotalLeftToPay, iFinanceLength);
buyers.push_back(Finance(sUserName, dCostOfChosenCar, sNameOfChosenCar, iFinanceLength, dDepositAmount, dMonthlyPayments, dTotalLeftToPay));
for (int iCount = 0; iCount != buyers.size(); iCount++) {
cout << "\nReceipt for: " << buyers[iCount].getUserName() << ". ";
cout << "\nYou have chosen " << buyers[iCount].getChosenCar() << ".";
cout << "\nYour finance plan timescale is " << buyers[iCount].getFinancePlan() << " " << YearOrYears(iFinanceLength) << ".";
cout << "\nYou've deposited £" << buyers[iCount].getDepositAmount() << ".";
cout << "\nTotal left to pay: £" << buyers[iCount].getTotalLeftToPay();
cout << "\nMonthly Payments: £" << buyers[iCount].getMonthlyAmount();
cout << "\n";
}
RestartOptions(cOption, bExit);
}
//This asks the user whether they're happy with the options of they've chosen.
void AcceptDeclineOptions(string& sUserName, int& iFinanceLength, double& dDepositAmount, bool& bExit, string& sNameOfChosenCar, double& dCostOfChosenCar, vector<Finance> buyers)
{
char cOption = 0;
do {
cout << "\nConfirm finance plan (y/n): ";
cin >> cOption;
cOption = toupper(cOption);
if (cOption == 'Y' || cOption == 'N') {
if (cOption == 'Y') {
Receipt(sUserName, iFinanceLength, dDepositAmount, cOption, bExit, sNameOfChosenCar, dCostOfChosenCar, buyers);
}
else {
RestartOptions(cOption, bExit);
}
}
else {
cout << "\nSorry, that's not a valid command.";
}
} while (cOption != 'Y' && cOption != 'N');
}
int main()
{
bool bExit = false;
int iFinanceLength = 0;
double dDepositAmount = 0;
string sNameOfChosenCar = "";
double dCostOfChosenCar = 0;
vector<cCar> car_list;
CarDatabase(car_list);
vector<cCar> car_purchases;
vector<Finance> buyers;
do {
cout << "Welcome!";
string sUserName = "";
cout << "\nEnter your name: ";
cin >> sUserName;
display_menu(car_list);
selectedCar(car_list, sNameOfChosenCar, dCostOfChosenCar);
FinanceLength(iFinanceLength);
DepositMoney(dDepositAmount);
AcceptDeclineOptions(sUserName, iFinanceLength, dDepositAmount, bExit, sNameOfChosenCar, dCostOfChosenCar, buyers);
} while (bExit == false);
}

What should I change or delete in order to fix this code so the rest may work fine?

#include <h1>iostream <h2>
#include <h1>cmath<h2>// for + of months, days, and years
#include <h1>fstream<h2> //for in and output
#include <h1>cstdlib<h2>
#include <h1>string<h2>//for string type
using namespace std;
class Device {//Input and store Device Description and Serial Numbers
protected:
string serial_number;
string device_description;
public:
Device() {
serial_number = ("6DCMQ32");
device_description = ("TheDell");
}
Device(string s, string d) {
serial_number = s;
device_description = d;
}
};
class Test {
protected:
string Test_Description;
static int recent_month, recent_day, recent_year, new_month;
static int nmonth, next_month, next_day, next_year, max_day;
public:
static void getMonth() {//Calculates the next/new month
next_month = recent_month + nmonth;
new_month = next_month % 12;
if (next_month >= 12) {
cout << "The next Date: " << new_month << " / ";
}
else {
cout << "The next Date: " << next_month << " / ";
}
}
static void getDay() { //Calculates day of next month
if (new_month == 4 || new_month == 6 || new_month == 9 || new_month == 11) {
max_day = 30;
}
else if (new_month == 2) {
max_day = 29;
}
else {
max_day = 31;
}
if (recent_day > max_day) {
cout << max_day << " / ";
}
else {
cout << recent_day << " / ";
}
}
static void getYear() {//Calculates the year of the next number of months
next_year = recent_year + next_month;
if (next_year >= 12) {
cout << recent_year + (next_month / 12) << endl;
}
else {
cout << next_year << endl;
}
}
static void getDate() {
Test::getMonth(), Test::getDay(), Test::getYear();
}
};
int Test::recent_month, Test::recent_day, Test::recent_year,
Test::new_month;
int Test::nmonth, Test::next_month, Test::next_day, Test::next_year,
Test::max_day;
class Lab : public Device, public Test {//Class Lab is a Child of Class Test and Class Device
protected:
static int n;
public:
friend istream & operator>>(istream & cin, const Lab & lab) {
cout << "Enter Device Description and serial number: ";
getline(cin, lab.device_description);//This is where the error is
getline(cin, lab.serial_number);//This is where the error is
cout << "Enter Test Description: ";
getline(cin, lab.Test_Description);//This is where the error is
cout << "Enter number of months: ";
cin >> lab.nmonth;
cout << "Enter the most recent date(mm/dd/yyyy): ";
cin >> lab.recent_month >> lab.recent_day >> lab.recent_year;
return cin;
}
friend ostream & operator<<(ostream & cout, const Lab & lab) {
cout << lab.device_description << " ";
cout << lab.serial_number << endl;
cout << lab.Test_Description << endl;
getDate();
return cout;
}
static void getFile() {
cout << "Enter the number of devices: ";
cin >> n;
Lab *obj = new Lab[n];
if (obj == 0) {
cout << "Memory Error";
exit(1);
}
for (int i = 0; i<n; i++) {
cin >> obj[i];
}
ofstream myfile("Device.dat", ios::binary);
myfile.write((char *)obj, n * sizeof(Lab));
Lab *obj2 = new Lab[n];
ifstream file2("Device.dat", ios::binary);
if (obj2 == 0) {
cout << "Memory Error";
exit(1);
}
file2.read((char *)obj2, n * sizeof(Lab));
for (int i = 0; i < n; i++) {
cout << obj2[i];
cout << endl;
}
delete[] obj2;
}
void getSearch(){
}
};
void main() {
Lab L;
L.getFile();
system("pause");
}
//Error C2665 'std::getline': none of the 2 overloads could convert all
the argument types
/*
Purpose: is to enter the number of months for the next test date of device with input of serial number, Device Description, Test Description, recent date, and the number of months of two tests. At the end the program must be searched by having the user to input the serial number and the next date, if these two are valid everything in the device is listed out.
*/<
You shouldn't name your parameters like objects of the standard library (cin).
For an argument to be modifiable it must not be a reference to a constant entity.
Also, a std::istream bound operator<<() overload should not do output, but only extract the object required from the stream.

Unhandled exception at 0x0F50DF58 : 0xC0000005: Access violation reading location 0x0047CA04

hi I write this following code after I debug when I try to read inside of my file after reading data when it returns from (printdata()) function i witness the following error can any one help me about this error?
Unhandled exception at 0x0F50DF58 : 0xC0000005: Access violation reading location 0x0047CA04.
////////////Library.h
#include <string>
using namespace std;
class Library
{
private:
string BookName;
string Author;
int Day,Month,Year ; //day month year
float Price;
string Subject;
double ISBN;
public:
Library(string = "", string = "", int = 0, int = 0, int = 0, float = 0.0, string = "", double = 0.0);
void setBookName(string);
void setAuthor(string);
void setPurchaseDay(int );
void setPurchaseMonth(int);
void setPurchaseYear(int);
void setPrice(float);
void setSubject(string);
void setISBN(double);
string getBookName();
string getAuthor();
int getPurchaseDay();
int getPurchaseMonth();
int getPurchaseYear();
float getPrice();
string getSubject();
double getISBN();
};
///////Linrary.cpp
#include "stdafx.h"
#include "Library.h"
#include <iostream>
#include <string>
using namespace std;
Library::Library(string bookname, string author,int day,int month,int year, float price, string subject, double isbn)
{
setBookName(bookname);
setAuthor(author);
setPurchaseDay(day);
setPurchaseMonth(month);
setPurchaseYear(year);
setPrice(price);
setSubject(subject);
setISBN(isbn);
}
void Library::setBookName(string bookname)
{
BookName = bookname;
}
void Library::setAuthor(string author)
{
Author = author;
}
void Library::setPurchaseDay( int day)
{
Day = day;
}
void Library::setPurchaseMonth(int month)
{
Month = month;
}
void Library::setPurchaseYear(int year)
{
Year = year;
}
void Library::setPrice(float price)
{
Price = price;
}
void Library::setSubject(string subject)
{
Subject = subject;
}
void Library::setISBN(double isbn)
{
ISBN = isbn;
}
///////////////////////////////////////////////
string Library::getBookName()
{
return BookName;
}
string Library::getAuthor()
{
return Author;
}
int Library::getPurchaseDay()
{
return Day;
}
int Library::getPurchaseMonth()
{
return Month;
}
int Library::getPurchaseYear()
{
return Year;
}
float Library::getPrice()
{
return Price;
}
string Library::getSubject()
{
return Subject;
}
double Library::getISBN()
{
return ISBN;
}
////////main function
#include "stdafx.h"
#include "Library.h"
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <cstdlib>
using namespace std;
int menu();
void EnterData();
void PrintData();
int main(int argc, char *arg[])
{
for (;;)
{
system("cls");
int c = menu();
switch (c)
{
case 1:
EnterData();
break;
case 2:
PrintData();
break;
case 8:
exit(0);
}//end of switch
}//end of for
}
int menu()
{
int p;
do
{
cout << "1. Enter Data of a Book." << endl;
cout << "2. Print Data of all Books." << endl;
cout << "3. Search a Book by Subject." << endl;
cout << "4. Search a Book by Auther." << endl;
cout << "5. Pirnt Books Purchased in a Period of Time." << endl;
cout << "6. Search by ISBN." << endl;
cout << "7. Price of Books Purchased in a Period of Time." << endl;
cin >> p;
} while (p < 0 || p>7);
cin.get();
return p;
}//end of menu() function
//***************Enter Data to File****************8
void EnterData()
{
system("cls");
ofstream fp("LIB.txt", ios::out | ios::trunc);
if (!fp)
{
cerr << "\nError in opening file to write in...";
cin.get();
exit(1);
}
Library data1;
cout << "\nEnter data of the book and write '.' instead of name to finilize."<<endl<<endl;
string bookname, author, subject;
int day, month, year;
float price;
double isbn;
do{
cout << "\nBook Name: ";
getline(cin, bookname);
data1.setBookName(bookname);
if (bookname == ".")
{
author = ".";
subject = ".";
price = 0.0;
isbn = 0;
day = month = year = 0;
data1.setAuthor(author);
data1.setSubject(subject);
data1.setPrice(price);
data1.setISBN(isbn);
data1.setPurchaseDay(day);
data1.setPurchaseMonth(month);
data1.setPurchaseYear(year);
fp.write((char*)(&data1), sizeof(Library));
return;
}
cout << "\nAuthor: ";
getline(cin, author);
data1.setAuthor(author);
cout << "\nPurchase Date (day,month,year): ";
cin >> day;
cin >> month;
cin >> year;
cin.ignore();
data1.setPurchaseDay(day);
data1.setPurchaseMonth(month);
data1.setPurchaseYear(year);
cout << "\nPrice: ";
cin >> price;
data1.setPrice(price);
cin.ignore();
cout << "\nSubject: ";
getline(cin, subject);
data1.setSubject(subject);
cout << "\nISBN: ";
cin >> isbn;
data1.setISBN(isbn);
cin.ignore();
fp.write((char*)(&data1), sizeof(Library));
} while (1);
fp.close();
cin.get();
}//enter of enterdata() function
//***************Print Data********************
void PrintData()
{
system("cls");
ifstream fp("LIB.txt", ios::in);
if (!fp)
{
cerr << "\nError in opening file to write in...";
cin.get();
exit(2);
}
Library data2;
string bookname, author, subject;
int day, month, year;
float price;
double isbn;
cout << left << setw(12) << "BookName" << setw(12) << "Author" << setw(12) << "PurchaseDate"
<< right<<setw(7) << "Price" << setw(12) << "Subject" << setw(7) << "ISBN"<<endl;
cout << "____________________________________________________________________"<<endl;
fp.read((char *)(&data2), sizeof(Library));
while ( fp && !fp.eof())
{
bookname=data2.getBookName();
author=data2.getAuthor();
day=data2.getPurchaseDay();
month = data2.getPurchaseMonth();
year = data2.getPurchaseYear();
price = data2.getPrice();
isbn = data2.getISBN();
subject = data2.getSubject();
//cout << left << setw(12) << bookname << setw(12) << author << setw(12) << purchasedate[0] << purchasedate[1] << purchasedate[2]
//<< right << setw(7) << price << setw(12) << subject << setw(7) << isbn << endl;
if (bookname.at(0) == '.')
{
fp.close();
break;
}
fp.read((char *)(&data2), sizeof(Library));
}
cin.get();
//fp.close();
//return;
}
disclaimer I am by no means a C programmer, and very well may be wrong here.
Your issues is probably coming from here:
fp.write((char*)(&data1), sizeof(Library));
You are passing the method data1, but telling it that the size of the file it should write is the size of Library, where it should be the size of data.
Library, being larger then data1, will cause a buffer overrun, where you will try reading a memory address outside of your application / variable.

What is a deleted function, and why only my functions that I pass files into are considered deleted? [duplicate]

This question already has answers here:
Using fstream Object as a Function Parameter
(3 answers)
Closed 6 years ago.
#include <bits/stdc++.h>
using namespace std;
class contact {
private:
vector< pair<string, int> > contact_info;
public:
void add_contact(string contact_name, int contact_number) {
contact_info.push_back(make_pair(contact_name, contact_number));
sort(contact_info.begin(),contact_info.end());
}
void edit_contact(string contact_name) {
int found_at;
for (unsigned int i =0; i < contact_info.size(); i++) {
if (contact_info[i].first == contact_name) {
found_at = i;
}
}
if (contact_info[found_at +1].first == contact_name) {
int choice;
int counter = found_at;
int index = 1;
while (contact_info[counter].first == contact_name) {
cout << index << ". " << contact_info[counter].first << " " << contact_info[counter].second;
counter++;
index++;
}
cout << "Choose any please: ";
cin >> choice;
found_at = found_at - (choice - 1);
}
cout << "Enter the new number: ";
cin >> contact_info[found_at].second;
}
void show_all() {
for (unsigned int i =0; i < contact_info.size(); i++) {
cout << contact_info[i].first << " " << contact_info[i].second << endl;
}
}
void delete_contact(string contact_name) {
int found_at;
for (unsigned int i =0; i < contact_info.size(); i++) {
if (contact_info[i].first == contact_name) {
found_at = i;
}
}
if (contact_info[found_at +1].first == contact_name) {
int choice;
int counter = found_at;
int index = 1;
while (contact_info[counter].first == contact_name) {
cout << index << ". " << contact_info[counter].first << " " << contact_info[counter].second;
counter++;
index++;
}
cout << "Choose any please: ";
cin >> choice;
found_at = found_at - (choice - 1);
}
contact_info.erase(contact_info.begin()+found_at);
}
void writeFile(ofstream contact_file) {
for (unsigned int i =0; i < contact_info.size(); i++) {
contact_file << contact_info[i].first << " " << contact_info[i].second << endl;
}
}
void readFile(ifstream contact_file) {
string input;
while (!contact_file.eof()) {
contact_file >> input;
size_t pos = input.find(" ");
string name = input.substr(0,pos);
string number_str = input.substr(pos);
int number = stoi(number_str) ;
contact_info.push_back(make_pair(name,number));
}
}
};
int main()
{
int choice;
ifstream contacts_file_read;
contacts_file_read.open("contacts.txt");
ofstream contacts_file_write;
contacts_file_write.open("contacts.txt");
bool in_prog = true;
contact contacts;
string name;
int number;
while (in_prog) {
cout << "1. Add contacts" << endl
<< "2. Edit contact" << endl
<< "3. Delete contact" << endl
<< "4. Show all" << endl
<< "5. exit" << endl;
cout << "Your choice: ";
cin >> choice;
contacts.readFile(contacts_file_read);
if (choice == 1) {
cout << "Enter name & number separated by a space: ";
cin >> name >> number;
contacts.add_contact(name, number);
} else if (choice == 2) {
cout << "Enter name of contacts to be edited: ";
cin >> name;
contacts.edit_contact(name);
} else if (choice == 3) {
cout << "Enter name of contact to be deleted: ";
cin >> name;
contacts.delete_contact(name);
} else if (choice == 4) {
contacts.show_all();
} else if(choice == 5) {
contacts.writeFile(contacts_file_write);
} else {
cout << "Wrong choice" << endl;
}
}
return 0;
}
So, I was asked in my programming class to make a phone book application in C++ using only objects, so this is my attempt at it.
All functions are good, I did recompile the program after finishing each function at it gave me 0 errors, however whenever I try to call writeFile or readFile function that were previously working fine, now the compiler gave me an error of "error: use of deleted functions... "
I don't know what are deleted functions and why only functions that take file objects as an argument are treated as such.
Can anyone please help?
Thanks.
Objects of type std::ifstream are not copyable -- indeed, the object represents the unique handle of an open file, and it would be difficult to conceptualize what it would mean to copy such unique responsibility.
Indeed, this inability to copy an object is encoded by making the copy constructor deleted, which causes the error that you see when you do attempt to copy it.
Your code should pass the original ifstream, not a copy (by taking a reference parameter):
void readFile(ifstream & contact_file)
// ^^^^^^^^^^