I am making a program in which I am storing class object in a vector and passing this vector to a friend function as const vector as reference variable and iterating it using const_vector, and I am trying to call member function of the class object using const_iterator so, I am getting error.But when I am doing this without const vector and iterating it without const_iterator then my program is running successfully.Is we can not iterate const_vector or we can not access member variable or function using const_vector.
vector<AccountHolder>::iterator searchAccount(const vector<AccountHolder>& v,long int accno)
{
vector<AccountHolder>::const_iterator itr;
for(itr = v.begin();itr!=v.end();itr++)
{
if(itr->getAccNo() == accno)return itr;
}
return v.end();
}
and this is the whole code.
#include<iostream>
#include<vector>
using namespace std;
class Account{
private:
long int AccNo;
char AccType;
public:
long int getAccNo()
{
return AccNo;
}
char getAccType()
{
return AccType;
}
void setAccNo(long int accno)
{
AccNo = accno;
}
void setAccType(char acctype)
{
AccType = acctype;
}
};
class AccountHolder:public Account{
private:
string Name;
public:
string getAccHolderName()
{
return Name;
}
void setAccHolderInfo(long int accno,char acctype,string name)
{
setAccNo(accno);
setAccType(acctype);
Name = name;
}
void displayAccountHolderInfo()
{
cout << "Name : " << getAccHolderName() << endl;
cout << "Account Number : " << getAccNo() << endl;
cout << "Account Type : " << getAccType() << endl;
}
friend void displayAllAccountHolder(vector<AccountHolder> &v);
friend vector<AccountHolder>::iterator searchAccount(vector<AccountHolder> &v,long int accno);
//friend bool searchAccount(const vector<AccountHolder> &v,long int accno,char acctype);
//friend vector<AccountHolder>::iterator searchAccount(const vector<AccountHolder> &v,long int accno=0,string name);
};
void displayAllAccountHolder(vector<AccountHolder> &v)
{
for(vector<AccountHolder>::iterator itr = v.begin();itr != v.end() ; itr++)
itr->displayAccountHolderInfo();
}
vector<AccountHolder>::iterator searchAccount(const vector<AccountHolder>& v,long int accno)
{
vector<AccountHolder>::const_iterator itr;
for(itr = v.begin();itr!=v.end();itr++)
{
if(itr->getAccNo() == accno)return itr;
}
return v.end();
}
int main()
{
vector<AccountHolder> Acc;
vector<AccountHolder> SavingAcc;
vector<AccountHolder> CurrentAcc;
vector<AccountHolder>::iterator temp;
AccountHolder AccH;
long int accno;
char acctype;
string name;
do{
cout << "Select Your Choice : " << endl;
cout << "1. Insert Data " << endl;
cout << "2. Display Data " << endl;
cout << "3. Display All User Data " << endl;
cout << "4. Exit " << endl;
cout << " Enter Your Choice : ";
int choice;
cin >> choice;
switch(choice)
{
case 1: cout << "\nEnter Name : ";
cin.get();
getline(cin >> ws,name);
accNo:
cout << "\nEnter Account Number : ";
cin >> accno;
if(searchAccount(Acc,accno)!=Acc.end())
{
cout << "\nAccount Number already exist." << endl;
goto accNo;
}
accType:
cout << "\nEnter Account Type : ";
cin >> acctype;
if(acctype == 's' || acctype =='S')
{
AccH.setAccHolderInfo(accno,'S',name);
SavingAcc.push_back(AccH);
Acc.push_back(AccH);
}
else if(acctype == 'c' || acctype == 'C')
{
AccH.setAccHolderInfo(accno,'C',name);
CurrentAcc.push_back(AccH);
Acc.push_back(AccH);
}
else
{
cout << "\n Invalid Account Type" << endl;
goto accType;
}
break;
case 2: cout << "\nEnter Account Number : ";
cin >> accno;
cout << "\nEnter Account Type(or just type 'n') : ";
cin.get();
cin >> acctype;
if(acctype == 's' || acctype == 'S')
temp = searchAccount(SavingAcc,accno);
else if(acctype == 'c' || acctype == 'C')
temp = searchAccount(CurrentAcc,accno);
else
temp = searchAccount(Acc,accno);
if(temp!=SavingAcc.end() && temp!=CurrentAcc.end() && temp!=Acc.end() )
temp->displayAccountHolderInfo();
else
cout << "\n Account does not exist. " << endl;
break;
case 3:displayAllAccountHolder(Acc);
break;
case 4: return 0;
break;
default:
break;
}
}while(true);
return 0;
}
but when you remove const vector to vector it will work.
vector::iterator searchAccount(const vector& v,long int accno)
Problem 1:
In order to invoke a method on a constant object, the method must be declared const (to declare that the hidden this parameter is const) and must not attempt to modify the object (because this is const). Simply not modifying the object inside the method isn't good enough. So
long int getAccNo()
{
return AccNo;
}
must be
long int getAccNo() const
{
return AccNo;
}
In fact, any time you have a function that does not or should not modify the object, you should declare it const out of general principles. This makes it easier for the compiler to trap mistakes for you and can save you a lot of debugging time.
Problem 2:
vector<AccountHolder>::iterator searchAccount(const vector<AccountHolder>& v,long int accno)
returns a vector<AccountHolder>::iterator, but inside the method you are using and trying to return vector<AccountHolder>::const_iterator. These are different, and incompatible, types, so one of them has to be changed. I recommend
vector<AccountHolder>::const_iterator searchAccount(const vector<AccountHolder>& v,long int accno)
Because the const_iterator is unavoidable with a const vector.
Related
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.
I'm a beginner at coding in C++ and every other language. The problem I'm having here is in main() with the first (else if) where (UserInput == sell). I would like the function to print the data stored in the object #listPos to retrieve the cost and input it into my incomplete Profit() function, but every time I dereference the pointer (Search) I get an error code. There's something I'm missing big time please help!!
Ive already tried (*search) but there's a huge error code.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class UnSold{
public:
UnSold(string NameOfShoe, int PurchasePrice ){
name = NameOfShoe;
cost = PurchasePrice;
return;
}
void SetName(string NameOfShoe){
name = NameOfShoe;
return;
}
void SetCost(int PurchasePrice){
cost = PurchasePrice;
return;
}
string GetName() const {
return name;
}
int GetCost() const{
return cost;
}
void Profit();
void PrintItem();
private:
string name;
int cost;
};
void UnSold::Profit(){
static int profit = 0;
//profit += (sold-cost);
}
void UnSold::PrintItem(){
cout << "Name: " << this->name << " Cost: " << this->cost << endl;
}
void PrintEverything(vector<UnSold*> AllItems) {
unsigned int i;
for (i=0; i<AllItems.size(); ++i) {
cout<< i+1 << " ";
(*AllItems.at(i)).PrintItem();
}
}
int main(){
vector<UnSold*> Inventory;
string Name;
int Cost;
string UserInput;
unsigned int listPos;
UnSold* newItem = nullptr;
UnSold* search = nullptr;
while ( UserInput != "quit") {
cout << "Do you want to add, sell, print or quit?" <<endl;
cin >> UserInput;
if ( UserInput == "add") {
cout << "Enter item name: "<<endl;
cin >> Name;
cout << "Enter item cost: " << endl;
cin >> Cost;
newItem = new UnSold(Name, Cost);
Inventory.push_back(newItem);
}
else if ( UserInput == "sell") {
cout << "List Positon: ";
cin >> listPos;
if ( listPos < Inventory.size()){
cout << " Item Sold and Removed from list position " << listPos <<endl;
search = Inventory.at(listPos-1);
//cout<< "contents of Search: "<< search << endl;
delete search;
Inventory.erase(Inventory.begin() + (listPos -1));
}
else{
cout << "Error"<<endl;
}
}
else if ( UserInput == "print") {
PrintEverything(Inventory);
}
else if ( UserInput != "quit"){
}
}
return 0;
}
This is a compile error.
Remove line 85: newItem.at(listPos - 1); and it runs just fine in visual studio.
The issue is that newItem is a pointer to an element. I assume you meant to use Inventory here instead. However, that logic was already done on the previous line.
On a side note, I stongly advise against storing owning pointers like this. There's no good reason in this case not to just use vector<UnSold> instead.
else if ( UserInput == "sell") {
cout << "List Positon: ";
cin >> listPos;
if ( listPos < Inventory.size()){
cout << " Item Sold and Removed from list position " << listPos <<endl;
search = Inventory.at(listPos-1);
//cout<< "contents of Search: "<< search << endl;
delete search;
Inventory.erase(Inventory.begin() + (listPos -1));
Here you mix the use of listPos and listPos - 1.
If you're allowing the user to input position 0 indexed, then
Inventory.at(listPos-1) should be Inventory.at(listPos) and
Inventory.erase(Inventory.begin() + (listPos -1)) should be Inventory.erase(Inventory.begin() + (listPos)).
If you're letting them input the position with the indexing starting at 1, then
if (listPos < Inventory.size()) should be
if(listPos <= Inventory.size() && listPos > 0)
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)
// ^^^^^^^^^^
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)?
I was wondering if there is a way to get a date without writing your own function. Something such as accessing the date set for the system. I tried
char dateStr[9];
_strdate(dateStr);
with the included time header, but I got compiler error ISO C++ forbids declaration of _strdate with no type. I thought _strdate was already declared and defined in the header so it wouldn't need a type definition. Could the problem be that I have those 2 lines inside of a struct? Are there any better way to store a date? Thanks.
#include "std_lib_facilities.h"
//Classes-----------------------------------------------------------------------
class Book{
public:
Book(){}; // default constructor
//operators
friend ostream& operator<<(ostream& out, const Book& val);
bool Book::operator==(const Book& check);
//member functions
string title();
string author();
string genre();
int copyright();
void ISBN();
bool checkout();
private:
string title_;
string author_;
string genre_;
int copyright_;
int ISBN1;
int ISBN2;
int ISBN3;
char ISBN4;
bool checkout_;
};
class Patron{
public:
Patron(){}; //default constructor
//member functions
string name();
int libnumber();
double setfee();
private:
string name_;
int libnumber_;
double libfees;
};
class Library{
public:
vector<Book> books;
vector<Patron> patrons;
struct Transaction{
Book book;
Patron patron;};
vector<Transaction> transactions;
};
// Error Function---------------------------------------------------------------
void _error(const string& s)
{
cout << endl;
cout << "Error: " << s << endl;
cout << endl;
}
// Book Member Functions--------------------------------------------------------
string Book::title()
{
cout << "Title: ";
getline(cin,title_);
cout << endl;
return title_;
}
string Book::author()
{
cout << "Author: ";
getline(cin,author_);
cout << endl;
return author_;
}
string Book::genre()
{
cout << "Genre(Fiction, Nonfiction, Periodical, Biography, Children): ";
cin >> genre_;
cout << endl;
if((genre_!="Fiction")&&(genre_!="Nonfiction")&&(genre_!="Periodical")&&
(genre_!="Biography")&&(genre_!="Children")) _error("Invalid genre.");
else return genre_;
}
int Book::copyright()
{
cout << "Copyright: ";
cin >> copyright_;
cout << endl;
return copyright_;
}
void Book::ISBN()
{
cout << "ISBN (4 entries. Use spaces): ";
cin >> ISBN1 >> ISBN2 >> ISBN3 >> ISBN4;
if((ISBN1<0) || (ISBN2<0) || (ISBN3<0) || (ISBN1>9) || (ISBN2>9) || (ISBN3)>9)
_error("Must be single digit.");
else if(!isdigit(ISBN4) && !isalpha(ISBN4))
_error("Must be single digit or letter.");
else{ cout << endl;
return;}
}
bool Book::checkout()
{
char check;
cout << "Checked out?(Y or N): ";
cin >> check;
switch(check){
case 'Y':
cout << endl;
return true;
break;
case 'N':
cout << endl;
return false;
break;
default:
_error("Must be Y or N.");}
}
// Patron Member Functions------------------------------------------------------
string Patron::name()
{
cout << "Name: ";
getline(cin,name_);
cout << endl;
return name_;
}
int Patron::libnumber()
{
cout << "Libnumber: ";
cin >> libnumber_;
cout << endl;
return libnumber_;
}
double Patron::setfee()
{
cout << "Fee due: ";
cin >> libfees;
cout << endl;
return libfees;
}
// Patron Helper Functions------------------------------------------------------
bool isfee()
{
char isfee_;
cout << "Does patron have fee due?(Y or N): ";
cin >> isfee_;
cout << endl;
if((isfee_!='Y') && (isfee_!='N')) _error("Must use Y or N.");
else return(isfee_=='Y');
}
// Operator Overloads-----------------------------------------------------------
ostream& operator<<(ostream& out, const Book& val){
out << "Title: " << val.title_ << endl;
out << "Author: " << val.author_ << endl;
out << "ISBN: " << val.ISBN1 << "-" << val.ISBN2 << "-" << val.ISBN3 << "-" << val.ISBN4 << endl;
out << endl;
return out;}
bool Book::operator==(const Book& check){
return((ISBN1 == check.ISBN1) && (ISBN2 == check.ISBN2) && (ISBN3 == check.ISBN3)
&& (ISBN4 == check.ISBN4));}
// Main Helpers-----------------------------------------------------------------
void runBook()
{
Library bookstore;
char notfinished;
bool bookfinished = false;
while(!bookfinished)
{
Book book;
book.title();
book.author();
book.genre();
book.copyright();
book.ISBN();
book.checkout();
bookstore.books.push_back(book);
cout << "Do you wish to store another book?(Y or N): ";
cin >> notfinished;
if(notfinished == 'Y'){
cin.ignore();
cout << endl;}
else if(notfinished == 'N'){
bookfinished = true;
cout << endl;}
else _error("Must be Y or N");
}
}
void runPatron()
{
Library patronstore;
bool patronfinished = false;
char notfinished;
while(!patronfinished)
{
Patron patron;
patron.name();
patron.libnumber();
if(isfee()){
patron.setfee();}
cin.ignore();
runBook(); // Call book function
patronstore.patrons.push_back(patron);
cout << "Is there another patron?(Y or N): ";
cin >> notfinished;
if(notfinished == 'Y'){
cin.ignore();
cout << endl;}
else if(notfinished == 'N') patronfinished = true;
else _error("Must be Y or N");
}
}
// Main-------------------------------------------------------------------------
int main()
{
runPatron();
keep_window_open();
}
If you go to class Library and into the Transaction struct, that is where I want to store the date.
Where to start? Difficult to tell without seeing the code, but here's some thoughts.
First, you should probably NOT store the date as a character array within your struct because that will make manipulation of it awkward. Better to store it in it's native form as a time_t, and convert it to/from strings as required.
Second, if you must store it as ascii, don't store it as char[]. You're just asking for buffer overruns etc. Use string or vector
However, I think the real answer to your question concerns constructors. If you want Transaction to hold a date, then define it like this
struct Transaction
{
char dateStr[9];
}
If you want transactions to be datestamped, then assign the date in the constructor
struct Transaction
{
char dateStr[9];
Transaction()
{
_strdate(dateStr); // or asctime or whatever
}
}
Now, whenever you create a Transaction, it will automatically be filled with the return value from _strdate, whatever that is. Here's how I'd do it with time_t.
#include <stdio.h>
#include <time.h>
struct Transaction
{
time_t theTime;
Transaction()
{
theTime = time(NULL);
}
}
There is no such standard C++ function as strdate. Whether putting those lines "inside a struct" causes a problem is impossible to say without seing the code. I suggest what you really want is the asctime() function, or one of its relatives.