Related
Making a project I have to write patient database and I have a problem. Looking through guids in iтternet I dont understand how to read from file to class and how to write class into file(I realized it using common input, it is better to rewrite it).
And I dont understand how to make base constructor for char, like with int
point()
{
x=y=z=0;
}
need like
Patient()
{
name="Mike";
surename="Smith";
adress="New York";
ilness="Cold"
card_number=1;
}
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int add();
int read();
string path = "base.txt";
class Patient
{
private:
char *name;
char *surename;
char *adress;
char *ilness;
int *card_number;
public:
void set()
{
cout << "Enter name:";
cin >> name;
cout << "Enter surename:";
cin >> surename;
cout << "Enter adress:";
cin >> adress;
cout << "Enter diagnosis:";
cin >> ilness;
cout << "Enter card number:";
cin >> *card_number;
}
void show()
{
cout << "Name:" << name << endl;
cout << "Surename:" << surename << endl;
cout << "Adress:" << adress << endl;
cout << "Cardnumber:" << card_number << endl;
cout << "Diagnosis:" << ilness << endl;
}
void print()
{
cout << name << surename << adress << ilness << card_number << endl;
}
Patient()
{
}
Patient(const char* s)
{
int length = 0;
while (s[length++] != ' ')
;
name = new char[length];
for (int i = 0; i < length; i++)
name[i] = s[i];
length = 0;
while (s[length++] != ' ')
;
surename = new char[length];
for (int i = 0; i < length; i++)
surename[i] = s[i];
length = 0;
while (s[length++] != ' ')
;
adress = new char[length];
for (int i = 0; i < length; i++)
adress[i] = s[i];
length = 0;
while (s[length++] != ' ')
;
ilness = new char[length];
for (int i = 0; i < length; i++)
ilness[i] = s[i];
length = 0;
while (s[length++] != '\n')
;
card_number = new int[length];
for (int i = 0; i < length; i++)
card_number[i] = s[i];
}
};
int main()
{
char a;
cout << "Choose the action:" << endl;
cout << "a. Add new patient" << endl;
cout << "b. Delete patient" << endl;
cout << "c. Find for card number" << endl;
cout << "d. Find for ilnesses" << endl;
cin >> a;
switch (a)
{
case 'a':
add();
break;
case 'b':
read();
break;
default:
cout << "error" << endl;
}
system("pause");
return 0;
}
int add()
{
fstream file;
file.open(path, fstream::out | fstream::in | ofstream::app);
if (!file.is_open())
{
cout << "Error" << endl;
}
else
{
string str;
cout << "Opend" << endl;
cout << "Enter name" << endl;
cin >> str;
file << str<<" ";
cout << "Enter surename" << endl;
cin >> str;
file << str << " ";
cout << "Enter adress" << endl;
cin >> str;
file << str << " ";
cout << "Enter ilness" << endl;
cin >> str;
file << str << " ";
cout << "Enter card number" << endl;
cin >> str;
file << str<<"\n";
cout << "Sucsesfully added\n";
}
file.close();
return 0;
}
int read()
{
fstream file;
file.open(path, fstream::out | fstream::in | ofstream::app);
if (!file.is_open())
{
cout << "Error" << endl;
}
else
{
cout << "Opend" << endl;
string str;
Patient first;
while (file.read((char*)&first,sizeof(Patient)))
{
first.print();
}
}
file.close();
return 0;
}
Database example
Mike Smith New_York Cold 1
Charles Williams London Flu 2
Henry Roberts York Coronovirus 3
Robert Garcia Sydney Cold 4
methods how to write from file to class and from class to file
If you want to serialise your data structures, it's best to use a library and data format, such as JSON.
Personally, I recommend nlohmann::json because of it's ease of use and flexibility.
Overloading the constructor and serialising data
Overloading your constructor is nothing other than overloading another method in C++.
If your class is Patient:
#include <string>
#include <nlohmann/json.hpp>
using nlohmann::json;
using std::string; // Don't use using namespace std;!
class Patient {
public:
Patient() = default;
explicit Patient(const string& name, const string& surname,
const string& addr, const string& illness):
m_name(name), m_surname(surname), m_address(addr), m_illness(illness) {}
explicit Patient(const json& data) { fromJson(data); }
virtual ~Patient() = default;
json toJson() const {
return {
{ "Name", m_name },
{ "Surname", m_surname },
{ "Address", m_address },
{ "Illness", m_illness }
};
}
void fromJson(const json& data) {
if (data.contains("Name") && data["Name"].is_string()) {
m_name = data["Name"].get<string>();
} // and so on
}
void dumpJson(const string& filePath) const {
ofstream out(path, std::ios::out);
// error checking
out << filePath;
}
private: // members
string m_name;
string m_surname;
string m_address;
string m_illness;
};
I haven't tested this code and won't guarantee it will work first try, but it should point you in the right direction. This code requires at least C++11.
I recently made an application with 1 superclass and 2 subclasses. The main idea of it is storing information in 3 different list. My question is, can you only use 1 list for all 3 classes? Even though the 2 subclasses have some extra members. Someone told me that you could use unique_ptr as a member of the superclass and make only 1 list. I have read about it on the internet, but I can't quite get it. Any suggestions? Thank you for your time.
class Student {
std::string Name;
std::string Pinfo;
std::map < std::string, float > Ngradelist;
public:
std::string getName() {return Name;}
std::string getPinfo() {return Pinfo;}
virtual void InsertGradeList(std::string a, float b) {
for(auto& it : Ngradelist)
Ngradelist.insert(std::pair <std::string, float > (a,b));
}
Student( std::string n, std::string p, std::map < std::string, float > Ng) :
Name(std::move(n)), Pinfo(std::move(p)), Ngradelist(std::move(Ng)) {}
virtual void Display() {
std::cout << "Name: " << Name << std::endl;
std::cout << "Personal information: " << Pinfo << std::endl;
std::cout << "NCourse:" << std::endl;
for(auto& it : Ngradelist)
std::cout << " " << it.first << " Grade: " << it.second << std::endl;
}
};
class HWStudent : public Student {
std::string FieldOfWork;
std::map<std::string, float> HWgradelist;
public:
void InsertGradeList(std::string a, float b) override{
for (auto &it : HWgradelist)
HWgradelist.insert(std::pair<std::string, float>(a, b));
}
HWStudent(std::string n, std::string p, std::map<std::string, float> Ng, std::string f,
std::map<std::string, float> HWg) : Student(std::move(n), std::move(p), std::move(Ng)),
FieldOfWork(std::move(f)), HWgradelist(std::move(HWg)) {}
void Display() override {
Student::Display();
std::cout << "Field of Work: " << FieldOfWork << std::endl;
std::cout << "HWCourse:" << std::endl;
for(const auto& it : HWgradelist)
std::cout << " " << it.first << " Grade: " << it.second << std::endl;
}
};
class SWStudent : public Student {
std::map<std::string, float> SWgradelist;
std::list < std::string > Languages;
public:
void InsertGradeList(std::string a, float b) override {
for (const auto &it : SWgradelist)
SWgradelist.insert(std::pair<std::string, float>(a, b));
}
SWStudent(std::string n, std::string p, std::map<std::string, float> Ng, std::list < std::string > l,
std::map<std::string, float> SWg) : Student(std::move(n), std::move(p), std::move(Ng)),
Languages(std::move(l)), SWgradelist(std::move(SWg)) {}
void Display() override {
Student::Display();
std::cout << "SWCourse:" << std::endl;
for(const auto& it : SWgradelist)
std::cout << " " << it.first << " Grade: " << it.second << std::endl;
std::cout << "SW Languages:" << std::endl;
for(const auto& it : Languages)
std::cout << " " << it << std::endl;
}
};
std::list < Student > listaStudenti;
std::list < HWStudent > HWlistaStudenti;
std::list < SWStudent > SWlistaStudenti;
void InsertListaStudenti(unsigned short option) {
unsigned short numbers;
std::string name , pinfo, course, fieldofwork, hwcourse, swcourse;
std::string language;
float grade = 0, hwgrade, swgrade;
std::list < std::string > languagelist;
if(option == 1) {
std::cout << "Insert name: ";
std::cin >> name;
std::cout << "Insert personal information: ";
std::cin >> pinfo;
std::cout << "Insert course: ";
std::cin >> course;
std::cout << "Insert grade: ";
std::cin >> grade;
Student student(name, pinfo, {{course, grade}});
listaStudenti.push_back(student);
}
if(option == 2) {
std::cout << "Insert name: ";
std::cin >> name;
std::cout << "Insert personal information: ";
std::cin >> pinfo;
std::cout << "Insert course: ";
std::cin >> course;
std::cout << "Insert grade: ";
std::cin >> grade;
std::cout << "Insert hwcourse: ";
std::cin >> hwcourse;
std::cout << "Insert hwgrade: ";
std::cin >> hwgrade;
std::cout << "Insert fieldofwork: ";
std::cin >> fieldofwork;
HWStudent hwstudent(name, pinfo, {{course, grade}}, fieldofwork,{{hwcourse, hwgrade}});
HWlistaStudenti.push_back(hwstudent);
}
if(option == 3) {
std::cout << "Insert name: ";
std::cin >> name;
std::cout << "Insert personal information: ";
std::cin >> pinfo;
std::cout << "Insert course: ";
std::cin >> course;
std::cout << "Insert grade: ";
std::cin >> grade;
std::cout << "Insert swcourse: ";
std::cin >> swcourse;
std::cout << "Insert swgrade: ";
std::cin >> swgrade;
std::cout << "How many languages: ";
std::cin >> numbers;
for(auto it = 0;it < numbers; ++it) {
std::cout << "Insert language: ";
std::cin >> language;
languagelist.push_back(language);
}
SWStudent swstudent(name, pinfo, {{course, grade}},languagelist,{{swcourse, swgrade}});
SWlistaStudenti.push_back(swstudent);
}
}
int main() {
unsigned short option = 10;
while(option != 0) {
std::cout << "1.Add student." << std::endl;
std::cout << "2.Add HW student." << std::endl;
std::cout << "3.Add SW student." << std::endl;
std::cout << "4.Display Student." << std::endl;
std::cout << "5.Display HW Student." << std::endl;
std::cout << "6.Display SW Student." << std::endl;
std::cout << "0 is for exit." << std::endl;
std::cout << "Option is : ";
std::cin >> option;
switch (option) {
case 0 : {
std::cout <<" You chose to leave.";
exit;
break;
}
case 1 : {
InsertListaStudenti(option);
break;
}
case 2 : {
InsertListaStudenti(option);
break;
}
case 3: {
InsertListaStudenti(option);
break;
}
case 4: {
for(auto &it : listaStudenti)
it.Display();
break;
}
case 5: {
for(auto &it : HWlistaStudenti)
it.Display();
break;
}
case 6: {
for(auto &it : SWlistaStudenti)
it.Display();
break;
}
}
}
}
You can indeed have
std::list<std::unique_ptr<Student>> students;
instead of
std::list<Student> listaStudenti;
std::list<HWStudent> HWlistaStudenti;
std::list<SWStudent> SWlistaStudenti;
with insertion similar to
Student student(name, pinfo, {{course, grade}});
students.push_back(std::make_unique<Student>(std::move(student)));
// or std::make_unique<Student>(name, pinfo, std::map<std::string, float>{{course, grade}})
HWStudent hwstudent(name, pinfo, {{course, grade}}, fieldofwork, {{hwcourse, hwgrade}});
students.push_back(std::make_unique<HWStudent>(std::move(hwstudent));
instead of
Student student(name, pinfo, {{course, grade}});
listaStudenti.push_back(student);
HWStudent hwstudent(name, pinfo, {{course, grade}}, fieldofwork,{{hwcourse, hwgrade}});
HWlistaStudenti.push_back(hwstudent);
Issue would be with your "filtering":
for (auto& student : SWlistaStudenti) {
student.Display();
}
becomes
for (auto& studentPtr : SWlistaStudenti) {
if (auto ptr = dynamic_cast<SWStudent*>(studentPtr.get())) ptr->Display();
}
but (to show only regular students (not HW/SW))
for(auto& student : listaStudenti) { student.Display(); }
becomes
for (auto& studentPtr : students) {
if (!dynamic_cast<SWStudent*>(studentPtr.get())
&& !dynamic_cast<HWStudent*>(studentPtr.get())) {
studentPtr->Display();
}
}
One list allows to treats them equality BTW:
To display all students:
for (auto& studentPtr : students) { studentPtr->Display(); }
instead of
for (auto& student : listaStudenti) { student.Display(); }
for (auto& student : HWlistaStudenti) { student.Display(); }
for (auto& student : SWlistaStudenti) { student.Display(); }
I am trying to add a customer to my vector and when I run my program the copy constructor is called. I am doing an assignment where I need a vector of customers and have to be able to add customers, display customers, find customers and load/store the data. Have I created the vector wrong? I am only new to c++ and really unsure about vectors.
Code from Main.cpp:
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
#include "Customer.h"
using namespace std;
void OutputFileStream();
void parseLine(const string& str);
void InputFileStream();
void save(vector<Customer> customers);
void load(vector<Customer>& customers);
void addCustomer(vector<Customer>& vect);
void displayAll(vector<Customer>& customers);
//void printActions();
vector<Customer> customers;
void OutputFileStream()
{
cout << "Creating and writing to file: Customer.txt" << endl;
ofstream outStream("customers.txt"); // write mode (overwrites existing data)
if (outStream.good())
{
int customerID = 150033;
outStream << "This is a line of text.\n";
outStream << "This is another line of text.\n";
outStream << "This is a line of text.\n";
int numOfPurchases = 4;
int purchases = 0;
outStream << customerID << "Mr" << "Jack" << "New" << numOfPurchases << purchases << endl;
//int *purchases = customers[0].getPurchases();
outStream.close(); // close file
cout << "File written.\n" << endl;
}
else
cout << "Unable to open file";
}
void parseLine(const string& str) {
stringstream strStream(str); //create string stream from the string
// int customerID;
string title;
string name;
string type;
//int numOfPurchases;
//int purchases;
string s;
int customerID = 150033;
getline(strStream, s, ';');
customerID = stoi(s);
getline(strStream, title, ';');
getline(strStream, name, ';');
getline(strStream, type, ';');
int numOfPurchases = 4;
getline(strStream, s, ';');
numOfPurchases = stoi(s);
int purchases = 0;
getline(strStream, s, ';');
purchases = stoi(s);
int* purchasesArray = new int[3];
purchasesArray[0] = (purchases & (255 << 16)) >> 16;
purchasesArray[1] = (purchases & (255 << 8)) >> 8;
purchasesArray[2] = purchases & 255;
for (int i = 0; i < 3; i++)
{
cout << purchasesArray[i];
}
cout << " CustomerID: " << customerID << "Title:" << title << " Name: " << name << " Type:" << type << " Number of Purchases: " << numOfPurchases << "Purchases: " << purchases << endl;
}
void InputFileStream() {
cout << "Reading from a semi-colon delimited txt file" << endl;
string line;
ifstream inStream("customers.txt"); //opens file as an input file stream
if (inStream.good()) //if the file is opened successfully and not empty
{
while (getline(inStream, line)) //reads line until false return
{
parseLine(line);
}
inStream.close();
}
else
cout << "unable to open file or the file is empty!";
}
void save(vector<Customer> customers)
{
ofstream out("customers.txt");
if(out)
{
for (Customer& c : customers)
{
out << c.save();
}
out.flush();
out.close();
}
else
{
cout << "Error Writing to File" << endl;
}
}
void load(vector<Customer>& customers)
{
ifstream in("customers.txt");
if (in) {
string line;
while (!in.eof())
{
getline(in, line);
if (line != "")
{
Customer c;
c.parse(line);
customers.push_back(c);
}
}
}
}
void addCustomer(vector<Customer>& customers) {
Customer customer;
cin >> customer;
customers.push_back(customer);
}
void displayAll(vector<Customer>& customers)
{
cout << "\nvector contains:\n";
for (Customer c : customers)
cout << c.getCustomerID() << " " << c.getTitle() << c.getName() << c.getNumOfPurchases() << c.getPurchases() << c.getType() << endl;
cout << endl;; //same as calling customer
}
//
//int getCustomerByPurchaseNumber(int numOfPurchases) {
// vector<Customer> customers;
// int pos = -1;
// for (int i = 0; i < customers.size(); i++) {
// if (customers.at(i).getNumOfPurchases() == numOfPurchases) {
// return i;
// }
// }
// return pos;
//}
//
//void findCustomerByPurchaseNumber(vector<Customer>& customers) {
// vector<Customer> customers;
// int numOfPurchases;
// cout << "Please Enter Your Purchase Number:" << endl;
// cin >> numOfPurchases;
// int pos = customers.get(pos);
// getCustomerByPurchaseNumber(numOfPurchases);
// if (pos == -1) {
// cout << "Number of Purchase Not Found! " << endl;
// return customers;
// }
// else {
// cout << "Number Of Purchase Found! " << endl;
//
// return customers* = customers;
// }
//
//}
int main()
{
vector<Customer> customers;
Customer c1 = { 150031, "Mr", "John", 5, 333,362,341, "New" };
customers.push_back(c1);
//InputFileStream();
/* Customer customer;
customer.setCustomerID(150032);
customer.setTitle("Mr");
customer.setName("Joey");
customer.setNumOfPurchases(3);
customer.setPurchases(366, 352, 334);
customer.setType("New");
cout << customer.getCustomerID() << endl;
cout << customer.getTitle() << endl;
cout << customer.getName() << endl;
cout << customer.getNumOfPurchases() << endl;
cout << customer.getPurchases() << endl;
cout << customer.getType() << endl;
*/
return 0;
}
Code from Customer.cpp:
#include "Customer.h"
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include<utility>
using namespace std;
//default constructor
Customer::Customer() {
}
//Full constructor
Customer::Customer(int customerID, string title, string name, int numOfPurchases, int purchase1, int purchase2, int purchase3, string type)
{
this->customerID = customerID;
this->title = title;
this->name = name;
this->numOfPurchases = numOfPurchases;
purchases = new int[3];
purchases[0] = purchase1;
purchases[1] = purchase2;
purchases[2] = purchase3;
this->type = type;
}
Customer::Customer(const Customer& source) //copy constructor
{
cout << "copy constructor called" << endl;
this->customerID = source.customerID;
this->title = source.title;
this->name = source.name;
this->numOfPurchases = source.numOfPurchases;
this->purchases = new int[3];
purchases[0] = source.purchases[0];
purchases[1] = source.purchases[1];
purchases[2] = source.purchases[2];
this->type = source.type;
}
//overloaded assignment operator=
Customer& Customer::operator= (Customer& otherCustomer)
{
cout << "Overloaded assignment operator= called" << endl;
//self-assignment guard
if (this == &otherCustomer)
return *this; //refernce to the same object
// copy data from the source (rhs) to this object (the destination)
name = otherCustomer.name;
//must make a new scores object to store a copy of the other student
if (purchases != nullptr)
delete[] purchases;
purchases = new int[3];
for (int i = 0; i < 3; i++) {
purchases[i] = otherCustomer.purchases[i];
}
//return this existing object so we can chain this operator
return *this;
}
string Customer::save()
{
stringstream out;
out << this->customerID << ";";
out << this->title << ";";
out << this->name << ";";
out << this->type << ";\n";
out << this->numOfPurchases << ";";
int* purchases = 0;
out.flush();
return out.str();
}
void Customer::parse(string line)
{
stringstream in(line);
string customerIDLine;
getline(in, customerIDLine, ';');
customerID = stoi(customerIDLine);
getline(in, title, ';');
getline(in, name, ';');
getline(in, type, ';');
string numOfPurchases;
getline(in, numOfPurchases, ';');
int s = stoi(numOfPurchases);
int* purchasesArray = new int[3];
purchasesArray[0] = (s & (255 << 16)) >> 16;
purchasesArray[1] = (s & (255 << 8)) >> 8;
purchasesArray[2] = s & 255;
}
void Customer::addCustomer(vector<Customer>& customers )
{
//after read data
int customerID;
cout << "Please Enter Customer ID: " << endl;
cin >> customerID;
string title;
cout << "Please Enter Title: " << endl;
getline(cin, title);
string name;
cout << "Please Enter Name: " << endl;
getline(cin, name);
string type;
cout << "Please Enter Type: " << endl;
getline(cin, type);
int numOfPurchases;
cout << "Please Enter Number of Purchases: " << endl;
cin >> numOfPurchases;
int purchase1;
cout << "Please Enter First Purchase: " << endl;
cin >> purchase1;
int purchase2;
cout << "Please Enter Second Purchase: " << endl;
cin >> purchase2;
int purchase3;
cout << "Please Enter Third Purchase: " << endl;
cin >> purchase3;
Customer c;
customers.push_back(c);
//Customer c();
}
Customer::~Customer() {
cout << "Destructor ~Customer called" << endl;
delete[] purchases;
}
// Overloaded insertion operator (Outputs Character object data as an output stream)
// Defined in header file as a "friend" function, as it is not a member function
//
ostream& operator<<(ostream& out, Customer& customer)
{
cout << "Customer details ( output by insertion operator<< )" << endl;
cout << "Customer ID: " << customer.customerID << endl;
cout << "Title: " << customer.title << endl;
cout << "Name: " << customer.name << endl;
cout << "Number of purchases: " << customer.numOfPurchases << endl;
cout << "Purchases: ";
for (int i = 0; i < 3; i++)
{
if (i > 0) cout << ",";
cout << customer.purchases[i];
}
cout << "Type: " << customer.type << endl;
return out;
}
istream& operator>> (istream& in, Customer& customer)
{
cout << "Enter Customer details ( using the extraction operator>> )" << endl;
cout << "Enter Customer ID: " << endl;
cin >> customer.customerID;
cout << "Enter Title: " << endl;
getline(cin, customer.title);
cout << "Enter Name: " << endl;
getline(cin, customer.name);
cout << "Enter Number of Purchases: ";
cin >> customer.numOfPurchases;
cout << "Enter Purchases: ";
cin >> customer.purchases[0];
cin >> customer.purchases[1];
cin >> customer.purchases[2];
cout << "Enter Type";
getline(cin, customer.type);
cout << endl;
return in;
}
int Customer::getCustomerID()
{
return customerID;
}
string Customer::getTitle()
{
return title;
}
string Customer::getName()
{
return name;
}
int Customer::getNumOfPurchases()
{
return numOfPurchases;
}
int* Customer::getPurchases()
{
return purchases;
}
string Customer::getType()
{
return type;
}
void Customer::setCustomerID(int customerID)
{
if (customerID < 1) {
cout << "Customer ID has to be equal to 1 or more" << endl; //Changed all the "throw invalid_argument" messages to cout as they were causing an issue with my main.cpp file and an abort message kept appearing every time I ran my main.cpp file.
}
this->customerID = customerID;
}
void Customer::setTitle(string title)
{
if (title.length() < 2) {
cout << "Title has to be more than or equal to 2 characters" << endl;
}
this->title = title;
}
void Customer::setName(string name)
{
if (name.length() < 4) {
cout << "Length of name should be more than or equal to 4 characters" << endl;
}
this->name = name;
}
//Got help ith this on stack overflow as I was using "&&" instead of using "||" for the if statement
void Customer::setNumOfPurchases(int numOfPurchases)
{
if(numOfPurchases <0 || numOfPurchases > 10000){
cout << "Number of purchases should be between 0 to 10000" << endl;
}
this->numOfPurchases = numOfPurchases;
}
void Customer::setPurchases(int purchase1, int purchase2, int purchase3)
{
if (purchase1 < 0 || purchase2 < 0 || purchase3 < 0) {
cout << "Purchases must be more than or equal to zero" << endl;
}
}
//Got help from stack overflow on comparing strings as I originally didnt use "type.compare"
void Customer::setType(string type) {
if (type.compare("New") !=0 || type.compare("Either") !=0) {
cout << "Type of purchase has to be New or Either" << endl;
}
}
Code from Customer.h:
#pragma once
#include<iostream>
using namespace std;
#include<string>
#include <vector>
class Customer
{
private:
int customerID;
string title;
string name;
int numOfPurchases;
int* purchases;
string type;
public:
Customer(); // default constructor
Customer(int customerID, string title, string name, int numOfPurchases, int purchase1, int purchase2, int purchase3, string type);
//copy overload assignment
Customer& operator=(Customer& otherCustomer);
Customer(const Customer& source);
string save();
void parse(string line);
void addCustomer(vector<Customer>& customers);
~Customer(); //destructor
//Getters and Setters
void setCustomerID(int customerID);
void setTitle(string title);
void setName(string name);
void setNumOfPurchases(int numOfPurchases);
void setPurchases(int purchase1, int purchase2, int purchase3);
void setType(string type);
int getCustomerID();
string getTitle();
string getName();
int getNumOfPurchases();
int* getPurchases();
string getType();
void printCustomer() {
cout << customerID << "," << title << "," << name << "," << numOfPurchases << "," << purchases << "," << type << endl;
}
friend std::ostream& operator<<(std::ostream& out, Customer& customer); // overloaded operator<<
friend istream& operator>> (istream& in, Customer& customer); // overloaded operator >>
};
Vectors hold objects. If you have an object outside of the vector there is no way to have that same object inside the vector. You can move from one instance to one in the vector (that will move the instances inner parts, but there are still two instances). push_back does make a copy of its parameter when it cannot be moved from.
As you have a constructor that takes all necessary parameters, you can use emplace_back to avoid the copy and construct the instance right in place in the vector:
customers.emplace_back( customerID, title, name, numOfPurchases, purchase1, purchase2, purchase3, type);
If you check reference on std::vector<T,Allocator>::push_back object can be added to vector either by being copied (option1) or being moved (option 2).
So you can create a move constructor for your customer class:
class_name ( class_name && );
And then call push_back using that move consturctor (option 2) on vector:
void push_back( T&& value );
The std::vector<Customer> holds the element by value so just using std::vector::push_back will copy your local object into the vector.
To mitigate this you could either implement move semantics and move the the Customer object like this:
#include <utility>
....
Customer c;
c.parse(line);
customers.push_back(std::move(c));
or construct the object in-place:
// Post c++17 you could use `push_back()` here as well as
// c++17 has mandatory copy elision.
customers.emplace_back(Customer{}); // or customers.emplace_back(); only
customers.back().parse(line);
Both solutions require c++11.
You could also store a reference/pointer and allocate the object on the heap.
std::vector<std::unique_ptr<Customer>> customerVector;
customer_vector.push_back(std::make_unique<Customer>());
// or customer_vector.push_back(std::make_shared<Customer>());
Or
std::vector<Customer*> customerVector;
// Beware for memory leaks, needs to be deleted.
// Basically never use code like this post c++11).
customer_vector.push_back(new Customer{});
Okay, so I have a parent class called employee and 3 subclass called manager,researcher and engineer. I made a vector and want to list them. this is the how I process the making.
vector <Employee*,Manager*> EmployeeDB;
Employee *temp;
temp = new Manager(first, last, salary, meetings, vacations);
EmployeeDB.push_back(temp);
I have no problem in making the vector, my concern is listing the info. all 3 subclasses have firstname, lastname and salary but they're difference is that they have different data members which is unique, example the Manager has the int value vacation and the Engineer has the int value experience so on and so forth.
Employee.h:
#include <iostream>
#include <string>
using namespace std;
#ifndef EMPLOYEE_h
#define EMPLOYEE_h
class Employee
{
public:
Employee();
Employee(string firstname, string lastname, int salary);
string getFname();
string getLname();
int getSalary();
virtual void getInfo();
private:
string mFirstName;
string mLastName;
int mSalary;
};
#endif
Employee.cpp:
#include "Employee.h"
#include <iostream>
#include <string>
using namespace std;
Employee::Employee()
{
mFirstName = "";
mLastName = "";
mSalary = 0;
}
Employee::Employee(string firstname, string lastname, int salary)
{
mFirstName = firstname;
mLastName = lastname;
mSalary = salary;
}
string Employee::getFname()
{
return mFirstName;
}
string Employee::getLname()
{
return mLastName;
}
int Employee::getSalary()
{
return mSalary;
}
void Employee::getInfo()
{
cout << "Employee First Name: " << mFirstName << endl;
cout << "Employee Last Name: " << mLastName << endl;
cout << "Employee Salary: " << mSalary << endl;
}
Main:
#include <vector>
#include <iostream>
#include <string>
#include "Employee.h"
#include "Engineer.h"
#include "Manager.h"
#include "Researcher.h"
using namespace std;
vector <Employee*> EmployeeDB;
Employee *temp;
void add()
{
int emp, salary, vacations, meetings, exp, c;
string first, last, type, school, topic;
bool skills;
do
{
system("cls");
cout << "===========================================" << endl;
cout << " Add Employee " << endl;
cout << "===========================================" << endl;
cout << "[1] Manager." << endl;
cout << "[2] Engineer." << endl;
cout << "[3] Researcher." << endl;
cout << "Input choice: ";
cin >> emp;
system("cls");
} while (emp <= 0 || emp > 3);
cout << "===========================================" << endl;
cout << " Employee Info " << endl;
cout << "===========================================" << endl;
cout << "Employee First name: ";
cin >> first;
cout << "Employee Last name: ";
cin >> last;
cout << "Employee Salary: ";
cin >> salary;
switch (emp)
{
case 1:
cout << "Employee numbers of meetings: ";
cin >> meetings;
cout << "Employee numbers of vacations: ";
cin >> vacations;
temp = new Manager(first, last, salary, meetings,vacations);
EmployeeDB.push_back(temp);
delete temp;
break;
case 2:
cout << endl;
cout << "[1]YES [2]NO" << endl;
cout << "Employee C++ Skills: ";
cin >> c;
if (c == 1)
{
skills = true;
}
else
{
skills = false;
}
cout << "Employee Years of exp: ";
cin >> exp;
cout << "(e.g., Mechanical, Electric, Software.)" << endl;
cout << "Employee Engineer type: ";
cin >> type;
temp = new Engineer(first, last, salary, skills, exp, type);
EmployeeDB.push_back(temp);
delete temp;
break;
case 3:
cout << "Employee School where he/she got his/her PhD: ";
cin >> school;
cout << "Employee Thesis Topic: ";
cin >> topic;
temp = new Researcher(first, last, salary, school, topic);
EmployeeDB.push_back(temp);
delete temp;
break;
}
}
void del()
{
}
void view()
{
for (int x = 0; x < (EmployeeDB.size()); x++)
{
cout << EmployeeDB[x]->getInfo();
}
}
void startup()
{
cout << "===========================================" << endl;
cout << " Employee Database " << endl;
cout << "===========================================" << endl;
cout << "[1] Add Employee." << endl;
cout << "[2] Delete Employee." << endl;
cout << "[3] List Employees." << endl;
cout << "[4] Exit." << endl;
cout << "Please Enter Your Choice: ";
}
int main(int argc, char** argv)
{
bool flag = true;
int choice;
do {
do
{
system("cls");
system("pause>nul");
startup();
cin >> choice;
} while (choice < 0 || choice >4);
switch (choice)
{
case 1:
add();
break;
case 2:
del();
break;
case 3:
view();
break;
case 4:
flag = false;
system("EXIT");
break;
}
} while (flag == true);
return 0;
system("pause>nul");
}
I am getting error on the view() function.
It says no operator<< matches these operands
binary '<<': no operator found which takes a right hand operand of type void etc etc.
The problem is that the getInfo has return type void and you are trying to put that return value into cout.
It's important to understand that the code std::cout << val actually calls the function operator<<(ostream& out, const objectType& val) where objectType is the type of 'val'.
In your case the type is void, and there is simply no implementation of operator<< that takes void as a type. hence the error "no operator found which takes a right hand operand of type void...".
In order to fix your issue you have a few options:
Change view() to be
for (...)
{
EmployeeDB[x]->getInfo();
}
Change getInfo() to return a string the info as you'd like:
std::string getInfo()
{
std::string info;
info =...
return info;
}
Create an operator<< for Employee and change view to call it:
view()
{
for (...)
{
std::cout << EmployeeDB[x];
}
}
In my assignment I was asked to create the Product class, and I have finished all the implementations except the "non-member IO operator". The question I found it very vague, it asks me to overload the << and >> operators to work with ostream and istream to read a Product from and print a Product to the console in order to make this main function work.
Here I see the main function has cout or cin to Product's derived class SItem, I wonder how I should implement the << >> operators to make the main work.
My main:
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include "Product.h"
#include <fstream>
#ifdef TAB
# undef TAB
#endif
#define TAB '\t'
using namespace std;
namespace sict {
class SItem :public Product {
public:
SItem(const char* theSku, const char * theName) :Product(theSku, theName) {}
SItem() {}
virtual std::fstream& store(std::fstream& file, bool addNewLine = true)const {
if (!isEmpty()) {
file.open("ms4.txt", ios::out | ios::app);
file << sku() << TAB << name() << TAB << quantity() << TAB << qtyNeeded() << TAB
<< int(taxed()) << TAB << price() << endl;
file.clear();
file.close();
}
return file;
}
virtual std::fstream& load(std::fstream& file) {
file.open("ms4.txt", ios::in);
char buf[2000];
double dbuf;
int ibuf;
file >> buf;
sku(buf);
file >> buf;
name(buf);
file >> ibuf;
quantity(ibuf);
file >> ibuf;
qtyNeeded(ibuf);
file >> ibuf;
taxed(ibuf != 0);
file >> dbuf;
price(dbuf);
file.clear();
file.close();
return file;
}
virtual std::ostream& write(std::ostream& os, bool linear)const {
return isEmpty() ? os : (os << sku() << ": " << name() << ", qty: "
<< quantity() << ", qtyNeeded:" << qtyNeeded()
<< ", Cost: " << fixed << setprecision(2) << cost());
}
virtual std::istream& read(std::istream& is) {
char buf[2000];
double dbuf;
int ibuf;
cout << "Sku: ";
is >> buf;
sku(buf);
cout << "Name (no spaces): ";
is >> buf;
name(buf);
cout << "Qty: ";
is >> ibuf;
quantity(ibuf);
cout << "Qty Needed: ";
is >> ibuf;
qtyNeeded(ibuf);
cout << "Is taxed? (1/0): ";
is >> ibuf;
taxed(ibuf != 0);
cout << "Price: ";
is >> dbuf;
price(dbuf);
return is;
}
};
}
void dumpFile(fstream& f) {
f.open("ms4.txt", ios::in);
char ch;
while (!f.get(ch).fail()) {
cout.put(ch);
}
f.clear();
f.close();
}
using namespace sict;
void test() {
double res, val = 0.0;
fstream F("ms4.txt", ios::out);
F.close();
SItem S;
SItem T;
SItem U;
cout << "Enter Product info: " << endl;
cin >> S;
SItem V = S;
S.store(F);
T.load(F);
cout << "T: (store, load)" << endl;
cout << T << endl;
cout << "S: " << endl;
cout << S << endl;
cout << "V(S): " << endl;
cout << V << endl;
cout << "U=T & op= :" << endl;
U = T;
cout << U << endl;
cout << "Operator == :" << endl;
cout << "op== is " << (T == "1234" ? "OK" : "NOT OK") << endl;
cout << "op+=: " << endl;
U += 10;
cout << U << endl;
cout << "op+=double : " << endl;
res = val += U;
cout << res << "=" << val << endl;
}
int main() {
fstream F("ms4.txt", ios::out);
F.close();
SItem S;
SItem U("4321", "Rice");
cout << "Empty Prouduct:" << endl << S << endl;
cout << "U(\"4321\", \"Rice\"):" << endl << U << endl;
cout << "Please enter the following information:" << endl;
cout << "Sku: 1234" << endl;
cout << "Name(no spaces) : Blanket" << endl;
cout << "Qty : 12" << endl;
cout << "Qty Needed : 23" << endl;
cout << "Is taxed ? (1 / 0) : 1" << endl;
cout << "Price : 12.34" << endl;
test();
cout << "Please enter the following information:" << endl;
cout << "Sku: 1234" << endl;
cout << "Name(no spaces) : Jacket" << endl;
cout << "Qty : 12" << endl;
cout << "Qty Needed : 23" << endl;
cout << "Is taxed ? (1 / 0) : 0" << endl;
cout << "Price : 12.34" << endl;
test();
dumpFile(F);
cout << "----The End" << endl;
return 0;
}
This is my Product.h:
namespace sict {
class Product : public Streamable {
char sku_[MAX_SKU_LEN + 1];
char * name_;
double price_;
bool taxed_;
int quantity_;
int qtyNeeded_;
public:
Product();
Product(const char*, const char*, bool = true, double = 0, int = 0);
Product(const Product&);
virtual ~Product();
Product& operator=(const Product&);
//setters
void sku(const char*);
void price(double);
void name(const char*);
void taxed(bool);
void quantity(int);
void qtyNeeded(int);
//getters
const char* sku()const;
double price()const;
const char* name()const ;
bool taxed()const;
int quantity()const;
int qtyNeeded()const;
double cost()const;
bool isEmpty()const;
//member operators
bool operator==(const char*);
int operator+=(int);
int operator-=(int);
};
double operator+=(double, const Product&);
std::ostream& operator<<(std::ostream& ostr, const Product& p);
std::istream& operator >> (std::istream& istr, Product& p);
}
All the functions have been implemented except the last two, which are the IO operators.
Streamable class is an abstract class that has no implementations.
You did this wrong in many ways.
Best approach in your case is do it like that.
First define interfaces for stream operations, for your products:
class IStreamPrintable
{
public:
virtual std::ostream& PrintToStream(std::ostream& outStream) const = 0;
};
class IStreamReadable
{
public:
virtual std::istream& ReadFromStream(std::istream& inputStream) = 0;
};
Secondly define stream operators which will use this interfaces.
std::ostream& operator<<(std::ostream& out, const IStreamPrintable& printObject)
{
return printObject.PrintToStream(out);
}
std::istream& operator>>(std::istream& input, IStreamReadable& readObject)
{
return printObject.ReadFromStream(input);
}
Now you Product can inherit this interfaces:
class Product
: public IStreamPrintable
, public IStreamReadable
{
…
};
You do not have to implement it immediately. You can implement those methods in specific product classes SItem and it will work out of the box.
Your method virtual std::fstream& store(std::fstream& file, bool addNewLine = true) is total mess. You are passing fstream object and opening some specific file on it. This is wrong since you are unable to write multiple objects to single file. Keep there ostream object and do not change is state (do only writing), so you could cascade calls and so you could avoid hard-coding a file name.