Matching constructor not found (C++) in HardwareStore Class - c++

I have been working on a hardware store application, where there is a HardwareRecordclass that stores information about each object in a store (ex: nuts, bolts, screws, and so forth).
The information is stored in a ".dat" file, but this is not important right now.
Here's my declaration of this class:
// Definition of HardwareRecord class
#ifndef __Initialize_Hardware_Store_File__HardwareRecord__
#define __Initialize_Hardware_Store_File__HardwareRecord__
#include <iostream>
class HardwareRecord
{
public:
HardwareRecord(const int& account=0,const std::string& name="",const std::string& description="",const double& price=0.0); //constructor
HardwareRecord operator=(HardwareRecord&);
//'set' and 'get' functions
void setAccountNumber(int);
int getAccountNumber() const;
void setName(std::string);
std::string getName() const;
void setPrice(double);
double getPrice() const;
void setDescription(std::string);
std::string getDescription() const;
void wipeRecord(); //set everything to blank
private:
int myAccountNumber;
std::string myName;
std::string myDescription;
double myPrice;
};
#endif /* defined(__Initialize_Hardware_Store_File__HardwareRecord__) */
Here's my class definition:
// Implementation of HardwareRecord class definition
#include <iostream>
#include "HardwareRecord.h"
using namespace std;
HardwareRecord HardwareRecord::operator=(HardwareRecord & aRecord)
{
this->myAccountNumber=aRecord.myAccountNumber;
this->myName=aRecord.myName;
this->myDescription=aRecord.myDescription;
this->myPrice=aRecord.myPrice;
return *this; //allow for cascaded overloading
}
HardwareRecord::HardwareRecord(const int& account,const string& name,const string&
description,const double& price)
{
setAccountNumber(account);
setName(name);
setPrice(price);
setDescription(description);
}
void HardwareRecord::wipeRecord()
{
setAccountNumber(0);
setName("");
setPrice(0);
setDescription("");
}
void HardwareRecord::setAccountNumber(int num)
{
if (num < 0)
{
throw invalid_argument("The account number is not in the valid range (greater or equal to 0)");
}
else
{
myAccountNumber=num;
}
}
int HardwareRecord::getAccountNumber() const
{
return myAccountNumber;
}
void HardwareRecord::setName(string name)
{
myName=name;
}
string HardwareRecord::getName() const
{
return myName;
}
void HardwareRecord::setPrice(double price)
{
if (price < 0)
{
throw invalid_argument("The price can not be less than zero");
}
else
{
myPrice=price;
}
}
double HardwareRecord::getPrice() const
{
return myPrice;
}
void HardwareRecord::setDescription(string description)
{
this->myDescription=description;
}
string HardwareRecord::getDescription() const
{
return myDescription;
}
The class described is supposed to be used in the following main.cpp file:
// Application that models a store's record of inventory
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstdlib>
#include <sstream>
#include "HardwareRecord.h" //HardwareRecord definition
using namespace std;
//enumeration of choices
enum Choices {WIPE_RECORDS,UPDATE,LIST,PRINT,DELETE,NEW,END,LAST};
std::ostream& operator<<(std::ostream& op,const Choices& choices)
{
//print the string corresponding to the value of enum type Choices
string output="";
switch (choices)
{
case WIPE_RECORDS:
output = "wipe records";
break;
case UPDATE:
output = "update records";
break;
case LIST:
output = "list records";
break;
case PRINT:
output = "print records";
break;
case DELETE:
output = "delete records";
break;
case NEW:
output = "add new record";
break;
case END:
output = "terminate application";
break;
case LAST:
output = "an option used to iterate over the values in the Choice enumeration";
break;
default:
cerr << "Error. invalid value is read";
exit(EXIT_FAILURE);
break;
}
op << output; //print output
return op;
}
//prototype of helper functions
int enterChoice();
void wipeRecords(fstream&);
void updateRecord(fstream&);
void listRecords(fstream&);
void createTextFile(fstream&);
void deleteRecord(fstream&);
void newRecord(fstream&);
int main()
{
//open file for reading and writinbg
fstream outRecord ("HardwareRecord.dat",ios::in|ios::out|ios::binary);
//exit program if fstream cannot open file
if (!outRecord)
{
cerr << "File could not be opened." << endl;
exit(EXIT_FAILURE);
}
int choice; //user's choice
//enable user to specify action
while ((choice=enterChoice()) !=END)
{
switch (choice)
{
case WIPE_RECORDS: //wipe all records clean
wipeRecords(outRecord);
break;
case UPDATE: //update a record
updateRecord(outRecord);
break;
case LIST: //list all current records
listRecords(outRecord);
break;
case PRINT: //print a record
createTextFile(outRecord);
break;
case DELETE: //delete a record
deleteRecord(outRecord);
break;
case NEW: //add a new record (if space allows)
newRecord(outRecord);
break;
default: //display error if user does not select valid choice
cerr << "Incorrect choice" << endl;
}
outRecord.clear();
}
return 0;
}
//enable user to input menu choice
int enterChoice()
{
//display avaliable options
cout << "\nEnter your choice:\n"<< endl;
Choices aChoice;
for (int c=WIPE_RECORDS; c < LAST; c++)
{
aChoice= (Choices) c;
cout << c << " - " << aChoice << endl;
}
cout << "\n?: ";
int menuChoice;
cin >> menuChoice;
return menuChoice;
}
void wipeRecords(fstream& theFile)
{
HardwareRecord temp;
for (int i=0; i < 100;i++)
{
//convert record from binary and assign to temp
//make temp "wipe itself"
}
}
Yes, I realize that many of the functions are defined by prototype, but are not actually declared. This will be done later after this very problem described shortly afterwards is fixed. Please direct your attention to the following piece of code, from this very file:
void wipeRecords(fstream& theFile)
{
HardwareRecord temp; //Here's where the error occurs: No Matching constructor!
for (int i=0; i < 100;i++)
{
//convert record from binary and assign to temp
//make temp "wipe itself"
}
}
Whenever I try to compile this project on my Mac (I use xCode), I get the following error for the line that is commented. The error is "No matching constructor for initialization of 'HardwareRecord'". However, I provide default values for the constructor of a HardwareRecord object, so the line
HardwareRecord temp;
should initialize without any problems.
What is going on? How can I fix this?

I think this is the problem. In your constructor, you use an std::string&, however, you never include <string> in your code!
Along with some other errors, compiling with G++ gives you:
prog.cpp:46:57: error: ‘string’ does not name a type
This may invalidate your default constructor.

HardwareRecord class should have default constructor, e.g., like this:
class HardwareRecord {
public:
HardwareRecord() : myAccountNumber(0),
myName(""),
myDescription(""),
myPrice(0.0f) {}
...
};
Your current constructor with default parameter values doesn't seem to be regarded as a 'Default Constructor'.

You're attempting to use a default constructor.
HardwareRecord temp;
But you've declared a constructor that takes arguments, as well as an assignment operator. The act of declaring a constructor that takes arguments means that the compiler will not generate a default constructor for you. So if you want one you'll have to declare one yourself OR use the constructor you've created.
EDIT
My answer above is NOT correct as the OP has provided defaults for all specified arguments.
In the case I specified the compiler will state something like:
error: no matching function for call to ‘Foo::Foo()’
But with defaults specified it will compile.
Small test:
-- foo.h
class Foo
{
private:
int _i;
public:
Foo( int i );
};
-- foo.cpp
#include "foo.h"
Foo::Foo( int i )
: _i( i )
{
}
int main()
{
Foo foo;
return 0;
}

Related

How do you compare and sort a specific parameter within a class?

My professor has asked us to make a program that will take a user's input and continue reading until the end of input. Only then, can the program output what the user has typed.
Input should be based on video title, it's url, comments made on the video, length (in minutes), and rating (in *).
For example:
United Break Guitars, https://www.youtube.com/watch?v+5YGc4zOqozo, Great example of one person getting a giant company to listen, 4.5, ***, Space Versus Tabs, https://www.youtube.com/watch?v=SsoOG6ZeyUl, Decide for yourself: spaces or tabs?, 2.83, ****
Up until what is explained, I have completed and tested to see if everything works. My problem is the next part of the project which requires the user to choose between Rating, Length, or title then sort them based on what the user chose.
If I chose Rating, then the input above should be sorted from highest rated video to lowest.
This is what I have so far:
#include <iostream>
#include <stdlib.h>
#include <cstring>
#include <algorithm>
using namespace std;
#include "video.h"
int main()
{
string user, url, comment, title;
int rating;
double length;
int i = 0, last = 0;
Video *videoObj[100];
Video *temp[100];
// specifies how the videos should be sorted
cin >> user;
cin.ignore();
while (getline(cin,title) ) {
getline(cin, url);
getline(cin, comment);
cin >> length;
cin >> rating;
cin.ignore();
videoObj[i] = new Video(title, url, comment, length, rating);
i++;
last++;
}
temp[i] = new Video(title, url, comment, length, rating);
if(user=="rating"){
for(int i = 0; i < last - 1; i++){
for(int j = i+1; j< last; j++){
if(videoObj[i] -> Rating(videoObj[j])) {
temp[i] = videoObj[i];
videoObj[i]= Rating(videoObj[j]);
Rating(videoObj[j]) = temp[i];
}
}
}
}
for(int i= 0; i < last; i++)
{
videoObj[i]->print();
}
//delete[] videoObj;
return 0;
}
video.cpp file:
#include <iostream>
#include <algorithm>
using namespace std;
#include "video.h"
Video::Video(string video_title, string video_link, string video_comment, double video_length, int video_number)
: title(video_title), link(video_link), comment(video_comment), length(video_length), rating(video_number)
{
}
bool Video::Rating(Video *videoObj) {
if(rating > videoObj-> rating )
{
return true;
}
else
{
return false;
}
}
void Video::print(){
string star;
switch(rating){
case 1:
star = "*";
break;
case 2:
star = "**";
break;
case 3:
star = "***";
break;
case 4:
star = "****";
break;
case 5:
star = "*****";
break;
}
cout << title << ", " << link << ", " << comment << ", " << length << ", " << star << endl;
}
void Video::temp(){
title, link, comment, length, rating;
}
video.h file:
#ifndef VIDEO_H
#define VIDEO_H
using namespace std;
class Video {
public:
Video(string video_title, string video_link, string video_comment, double video_length, int video_number);
void print();
bool Rating(Video *videoObj);
void temp();
private:
string title;
string link;
string comment;
double length;
int rating;
};
#endif
I honestly have no idea how to implement the bubble sort correctly. I have looked up multiple different videos on youtube and posts on stackoverflow, but I can't seem to figure out how to sort a specific parameter within my class.
My professor gave us these instructions for sorting within our class:
When sorting the videos you need to be able to determine how two video objects should be
ordered. The easiest way to do this is to write member functions to handle the comparisons in
class Video. For example, this method could be used when sorting the videos by length:
// return true if the current video is longer than the given video (other) ,
// otherwise return false
bool Video :: longer(Video *other) {
return (mlength > other -> mlength ;
}
I'm not even sure if I did that part correctly in my video.cpp file. Any ideas on how I can get the sorting method to work properly?
Please be gentle, I'm very new to programming. I realize my bubble sort is wrong as well, I just don't know where to start fixing it...
I'd normally use std::sort with a comparison operator for each field you want to be able to compare. You can implement those either as named classes:
struct by_title {
bool operator()(Video const &a, Video const &b) {
return a.title < b.title;
}
};
struct by_rating {
bool operator()(Video const &a, Video const &b) {
return a.rating < b.rating;
}
};
// ...
std::sort(videos.begin(), videos.end(), by_rating);
std::sort(videos.begin(), videos.end(), by_title);
...or you can use a lambda expression to define a comparison:
// sort by rating
std::sort(videos.begin(), videos.end(), [](auto &a, auto &b) { return a.rating < b.rating; });
// sort by title
std::sort(videos.begin(), videos.end(), [](auto &a, auto &b) { return a.title < b.title; });

Retrive data using pointers to objects in c++

This a menu based program to create a database of people and for performing operations on their name. After compilation, I am able to add a person successfully using the add function of Person class but when I retrieve the list of the added people using list function it shows garbage values instead of showing the entered names. It's the question no. 4(lab 4) in the below give doc.
https://drive.google.com/open?id=18cR9bgPlqM6q-kXBIcxg5Hpj04bkZMnW&authuser=0
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
using namespace std;
class Person
{
const char *name;
public:
Person(const char* n)
{
name=n;
}
bool search(const char* substr)
{
const char *str=name;
while(*str!='\0')
{ int count=0;
if(*str==*substr)
{ const char *s=substr;
const char *p=str;
while(*s!='\0')
{
if(*p==*s)
{
count++;
p++;
s++;
}
else
break;
}
}
if(count==strlen(substr))
{
cout<<name<<endl;
return true;
}
str++;
}
return false;
}
void print()
{
cout<<name<<endl;
}
~Person()
{
cout << ":)";
}
friend class People;
};
class People
{
Person** array;
int length;
void prompt()
{
cout << "\n'A'-Add a person\n'L'-List all persons\n'S'-Search\n'Q'-Quit\n";
}
public:
People()
{
array = NULL;
length = 0;
}
void add()
{
string m;
cout << "Enter a Name:\n";
cin >> m;
Person s(m.c_str());
if (array == NULL)
array = (Person**)malloc(sizeof(Person*));
else
{
array=(Person**)realloc(array, length*sizeof(Person*));
}
array[length] =new Person(s.name);
array[length]->print();
++length;
}
void list()
{
cout << "\nThe names of the person in the list are:\n";
for (int i = 0; i <length; i++)
{
array[i]->print();
}
}
void search()
{
string a;
int flag = 0;
cout << "\nEnter a string to be found in the names present in the list:\n";
cin >> a;
cout << "\n The names with entered substring are:\n";
for (int i = 0; i <length; i++)
{
bool state=array[i]->search(a.c_str());
if (state)
flag = -1;
}
if (flag == 0)
cout << "\nNone of the names contains the entered substring!!!\n";
}
void menu()
{
char c = 'Y';
while (c != 'Q')
{
cout << "Choose an option(character):\n";
prompt();
cin>>c;
switch (c)
{
case 'A':add();
cout << "Name entered sucessfully!!!\n";
break;
case 'L':list();
break;
case 'S':search();
break;
case 'Q':c = 'Q';
break;
}
}
}
};
int main()
{
People All;
All.menu();
return 0;
}
I am not able to find any mistake in my implementation of add function. What could be the possible reason for malfunctioning of list function?
tl;dr
You store a pointer to the internal memory of string (m). That string gets destroyed at the end of add() so you have pointer to unallocated memory, which causes undefined behaviour.
possible solutions
Best would be to store a std::string instead of a const char * inside Person.
walkthrough
If you want a more detailed analyses: You store a pointer to a string that goes out of scope.
void add()
{
string m; // string is initialized and allocates memory for its content
cout << "Enter a Name:\n";
cin >> m; // read content
Person s(m.c_str()); // m.c_str() retrieves a pointer to the memory allocated by m
//this pointer is stored inside s
if (array == NULL)
{
array = (Person**)malloc(sizeof(Person*));
}
else
{
array=(Person**)realloc(array, length*sizeof(Person*));
}
array[length] = new Person(s.name); // s.name still points to the memory allocated by m
array[length]->print();
++length;
} //At the end of the function m gets destroyed and deallocates its memory
So after the function exits you still have stored the pointer to m.c_str() inside a persons name. This pointer now points to unallocated memory. This memory now may (or may not) be overwritten at any time. You get undefined behaviour and print garbage.

Issue With My School Assignment on Classes

So I have an assignment due in my C++ class on classes, and I'm having some trouble. Here is the description of the assignment:
Programming Challenge 7 on page 499 of your text asks you to design and Inventory Class that can hold information for an item in a retail store's inventory. You are given the code for the creation of the class along with code for the implementation of the functions. Demonstrate the class by writing a simple program that uses it. This program should demonstrate that each function works correctly. Submit your .cpp file using the link provided.
And here are the contents of the file sent (it's quite lengthy):
// Chapter 7---Files for Programming Challenge 13---Inventory Class
// This is the inventory.h file.
// It contains the Inventory class declaration.
#ifndef INVENTORY_H
#define INVENTORY_H
class Inventory
{
private:
int itemNumber;
int quantity;
double cost;
double totalCost;
public:
// Default constructor
Inventory()
{ itemNumber = quantity = cost = totalCost = 0; }
// Overloaded constructor
Inventory(int, int, double); // Defined in Inventory.cpp
// Mutators (i.e., "set" functions) defined in Inventory.cpp
void setItemNumber(int);
void setQuantity(int);
void setCost(double);
// setTotalCost calculates the total cost
// and stores the result in the totalCost member
void setTotalCost()
{ totalCost = cost * quantity; }
// Accessors (i.e., "get" functions)
int getItemNumber()
{ return itemNumber; }
int getQuantity()
{ return quantity; }
double getCost()
{ return cost; }
double getTotalCost()
{ return totalCost; }
// Input validation functions
bool validInt(int);
bool validFloat(double);
};
#endif
// This is the inventory.cpp file.
// It contains the Inventory class function definitions.
#include <iostream>
#include "Inventory.h"
using namespace std;
//************************************************************
// Overloaded constructor
// Accepts arguments to be stored in each member variable.
//************************************************************
Inventory::Inventory(int in, int q, double c)
{
setItemNumber(in);
setQuantity(q);
setCost(c);
setTotalCost();
}
//************************************************************
// setItemNumber accepts an argument to be stored in item number.
//************************************************************
void Inventory::setItemNumber(int in)
{
while (!validInt(in))
{
cout << "Item Number must be positive. Please re-enter: ";
cin >> in;
}
itemNumber = in;
}
//************************************************************
// setQuantity accepts an argument to be stored in quantity.
//************************************************************
void Inventory::setQuantity(int q)
{
while (!validInt(q))
{
cout << "Quantity must be positive. Please re-enter: ";
cin >> q;
}
quantity = q;
}
//************************************************************
// setCost accepts an argument to be stored in cost.
//************************************************************
void Inventory::setCost(double c)
{
while (!validInt(c))
{
cout << "Cost must be positive. Please re-enter: ";
cin >> c;
}
cost = c;
}
//************************************************************
// The validInt member tests its integer argument to see
// if it is negative. If the argument is negative, the function
// returns false. Otherwise, the function returns true.
//************************************************************
bool Inventory::validInt(int value)
{
if (value < 0) // the value is negative so it is NOT valid
return false;
else // the integer value is valid
return true;
}
//************************************************************
// The validFloat member tests its floating-point argument to see
// if it is negative. If the argument is negative, the function
// returns false. Otherwise, the function returns true.
//************************************************************
bool Inventory::validFloat(double value)
{
if (value < 0) // the value is negative so it is NOT valid
return false;
else // the floating-point value is valid
return true;
}
I'm just not sure how to use this information to make a program that demonstrates the class, and it could be as simple as me not saving the file the correct way
Just write a main function which instantiates an Inventory object and calls each of its methods in a meaningful way. This isn't a puzzle, just find a way to call the functions that makes sense to you.

Binary Tree template, class specific function call

Ok just a heads up, this is my first question on here so i apologize if I don't include every relevant piece of info on my first go, but I'll do my best.
My problem is with a specific function I'm trying to write in main() that will print out data from nodes if their "category" matches the category that is searched for. I'm likely just fumbling with syntax as I'm still pretty new at this. To be clear, the exact problem is that all the function calls I've tried tell me *****"No instance of Overloaded function "BinTree::inOrderTraverse [with Type=CategorizedContact]" matches the argument list. argument types are: (void). Object type is BinTree***** Here's the relevant main() code:
#include <iostream>
#include <string>
#include <stdexcept> //invalid_argument
using namespace std;
#include "name.h"
#include "contact.h"
#include "address.h"
#include "BinTree.h"
#include "BinNode.h"
#include "CategorizedContact.h"
#include "Field.h"
#include "htmlfunc.h"
using namespace AddressInfo;
void printMenu();
void printByCat(CategorizedContact&, int);
int getMenuInput();
int validateMenuInput(Field input);
Field printCategoryMenu();
Field categorySelection();
int main()
{
Address tmpAddress;
Name tmpName, tmpName2;
CategorizedContact tmpContact, tmpContact2, itemToRemove;
BinTree<CategorizedContact> myBook;
Field tmpString1, categoryIn;
int menuOption = 0, node = 0, count = 0, categoryMenuOption = 0, categoryInt = 0;
CategorizedContact& tmp = tmpContact2; // I was just experimenting with trying to initialize
//a ref variable here, to make the function call work.
myBook.readFile("address.csv");
do
{
printMenu();
menuOption = getMenuInput();
switch (menuOption)
{
case 1:
cout << "\t***** Add Contact *****\n\n";
categoryIn = categorySelection(); //Prints Category menu and gets input
tmpContact.setCategory(categoryIn); //Assigns category choice to tmpContact
cin >> tmpContact; //Gets the rest of the contact info
myBook.addItem(tmpContact); //Adds contact to address book
myBook.writeFile("address.csv", '\n'); //Writes new contact to file
break;
case 2:
cout << "\n\t***** Count Contacts *****\n";
count = myBook.getNumUsed();
cout << "Number of Contacts: " << count;
cout << endl << endl;
break;
case 3:
cout << "\n\t***** Print Contacts By Category *****\n";
categoryIn = printCategoryMenu(); //Prints category menu and gets choice
if (categoryIn == "All Contacts")
myBook.printAll();
categoryInt = stoi(categoryIn); // converts to int to match required function parameters
myBook.inOrderTraverse(printByCat(tmp, categoryInt));
break;
That last line before the break; is the function call I'm struggling with.
Here's it's declaration:
void printByCat(CategorizedContact& tmp, int categoryInt)
{
int count = 1;
switch (categoryInt)
{
case 65:
if (tmp.getCategory() == "Business")
cout << count << ". " << tmp << endl;
break;
default:
cout << "Error" << endl;
break;
}
}
It's unfinished, and probably not even designed correctly but I can't tell until i manage to get the function call working.
Lastly here's the relevant code from my inOrderTraverse .h and .tem files pertaining to the problem.
#ifndef BINTREE_H
#define BINTREE_H
#include <cstdlib> // NULL
#include <string>
#include <iostream> // cout
#include <fstream>
#include <algorithm> // copy
#include "BinNode.h"
#include "CategorizedContact.h"
#include "Contact.h"
template <class Type>
class BinTree
{
public:
BinTree();
BinTree(const BinTree<Type>& source);
~BinTree();
BinTree<Type>& operator=(const BinTree<Type>& source);//assignment operator
int getNumUsed() const { return(used); }
void addItem(Type dataIn);
void printAll();
void writeFile(string fileName, char delimeter = '\n');
void readFile(string fileName);
void inOrderTraverse(void process(Type&, int));
void debugOn() { debug = true; }
void debugOff() { debug = false; }
private:
bool debug;
int used;
BinNode<Type>* root;
void inOrderTraverse(void process(Type&, int),
BinNode<Type>* cursor, int& count);
void write(BinNode<Type>* cursor, char delimeter,
ofstream& outFile);
void printInOrder(BinNode<Type>* cursor, int& count);
void free(BinNode<Type>* cursor);
void copyTree(BinNode<Type>* cursor);
BinNode<Type>* alloc(Type itemToAdd);
};
#include "BinTree.tem"
And just the relevant .tem portions...
template <class Type>
void BinTree<Type>::inOrderTraverse(void process(Type&, int))
{
int count = 1;
inOrderTraverse(process, root, count);
}
template <class Type>
void BinTree<Type>::inOrderTraverse(void process(Type&, int),
BinNode<Type>* cursor, int& count)
{
if (cursor != NULL)
{
// In order traverse
inOrderTraverse(process, cursor->left, count);
// PROCESS
process(cursor->data, count);
count++;
inOrderTraverse(process, cursor->right, count);
}
}
Before anyone suggests changing the InOrderTraverse(void process(Type&, int)), or the overloaded version, just Know that I'm required to implement it that way for my project.
the only freedom i have is with ***printByCat(CategorizedContact, int)****, that can be changed as long as it's still compatible with inOrderTraverse.
So as i hope u can now see, the function in main() printByCat() is meant to take in a category from the user, and then serve as an argument itself for inOrderTraverse(printByCat()). but I'm obviously making a fundamental mistake that i don't understand.
At this point any guidance would be appreciated, I'm not asking anyone to do the coding for me as i know you are against that, but I really just need to understand why the function call isn't working. I'm guessing the problem stems from my lack of experience with reference variables, but The error I'm getting seems to suggest the function printByCat() which is being taken as an argument of inOrderTraverse, does not meet the argument requirements because it's not a void function, but it is a void function.... so yea I'm a little lost. Anyways thanks for your time, and please let me know if i forgot anything.
Found out what it was, apparently I can't include the arguments of printbyCat() when using this function as an argument of inOrderTraverse(), so the function call should have simply been: myBook.inOrderTraverse(printByCat).

I/O overloading and reading from text files

I need to define a read and a print function for a class that has an array of objects as a private variable. I have to read in objects from a text file and print them to the screen. To do this I need to overload the << and >> operators. I understand I need to use loops to read and print the information stored in the array but I'm not sure how to accomplish this. My lecturer has given us a skeleton code which is basically function prototypes and the main function which I need to stick to. I understand how this works with public structs as I have done this exact scenario using that but the private variables of class' are tripping me up.
class EmployeeList {
public:
//Constructors
EmployeeList();
EmployeeList(istream&);
//Accessors
bool isEmpty() const;
bool isFull() const;
int size() const; //Number of employees in list
Employee item(int i) const; //i'th employee
//Mutators
void setItem(int i,const Employee& e);
//I/O functions, sets the i'th emplyee to e
void read(istream&);
void print(ostream&) const;
private:
enum {MAXSIZE = 100};
Employee list[MAXSIZE];
int count; //Number of employees in the current list
};
EmployeeList::EmployeeList() {
count = 0;
}
EmployeeList::EmployeeList(istream& in) {
//list[MAXSIZE] = in;
}
bool EmployeeList::isEmpty() const {
return (count == 0);
}
bool EmployeeList::isFull() const {
return (count == MAXSIZE);
}
int EmployeeList::size() const {
return count;
}
Employee EmployeeList::item(int i) const {
}
void EmployeeList::setItem(int i, const Employee& e) {
}
void EmployeeList::read(istream& in) {
Employee tempList;
while (in >> tempList) {
}
}
void EmployeeList::print(ostream& out) const {
for (int i=0; i < size(); i++) {
}
cout << out;
}
The above part is the Class EmployeeList while the below part are overloading functions. The commented out parts are ideas that I thought might work but didn't.
istream& operator>>(istream& in, EmployeeList& l) {
l.read(in);
return in;
}
ostream& operator<<(ostream& out, const EmployeeList& l) {
l.print(out);
return out;
}
Below is the main function given to us.
int main() {
authorInfo();
ifstream infile("a1in.txt");
if(!infile) {
cout << "file 'alin.txt' not found.";
return EXIT_FAILURE;
}
EmployeeList theList(infile);
cout << endl;
cout << theList.size() << " employees read:\n" << theList << endl;
process(theList);
return EXIT_SUCCESS;
}
Hope someone can steer me in the right direction! Let me know if you need more of the code. Thanks!
EDIT:
Employee read and print functions:
void Employee::read(istream& in) {
in >> name >> id >> salary;
}
void Employee::print(ostream& out) const {
out << getName() <<" "<< getID() <<" "<< getSalary() << endl;
}
Employee overloading:
istream& operator>>(istream& in, Employee& e) {
e.read(in);
return in;
}
ostream& operator<<(ostream& out, const Employee& e) {
e.print(out);
return out;
}
EDIT 2: Updated read() function. The line with the while is where the error is.
void EmployeeList::read(istream& in) {
Employee inEmployee;
while (in >> inEmployee && count < MAXSIZE) {
list[count] = inEmployee;
count++;
}
}
EDIT 3: Here is the print() function I have so far. It does indeed print but I get the default constructor information rather than information from the file. Is this a read or print function issue? I'm thinking read function still.
void EmployeeList::print(ostream& out) const {
cout << endl;
for (int i=0; i < count; i++) {
out << list[count];
}
}
Array Bounds
In your class, you have:
Employee list[MAXSIZE];
Given this, there is an error the code you tried:
EmployeeList::EmployeeList(istream& in) {
list[MAXSIZE] = in;
}
list only has elements from list[0] to list[MAXSIZE - 1]. list[MAXSIZE] is one past the end of the array, and is invalid.
Constructors
That said, I'd strongly recommend against having a constructor that takes an istream&. It is far better to construct an empty object with the default constructor, then use its read(istream&) method (via operator <<) to load the data. In other words, rather than:
EmployeeList theList(infile);
use:
EmployeeList theList;
infile >> theList;
If you're required to have a constructor that takes an istream&, just have it call read() after initializing the object:
EmployeeList::EmployeeList(istream& in): count(0) {
read(in);
}
Note that only one constructor is called, so the initialization in EmployeeList::EmployeeList() does not happen in EmployeeList::EmployeeList(istream&). I hear the new version of C++ deals with this unnecessary repetition, but for the time being that's where we are.
Naming
Another thing: your code will be less confusing with better variable names. In this case:
void EmployeeList::read(istream& in) {
Employee tempList;
while (in >> tempList) {
}
}
Don't say tempList because it's not a "temporary list", it's a single Employee that has been read. Better would be:
void EmployeeList::read(istream& in) {
Employee inEmployee;
while (in >> inEmployee) {
list[count++] = inEmployee;
}
}
This looks like a homework so i'll try to just give you a hint:
void EmployeeList::read(istream& in) {
Employee tempList;
while (in >> tempList) {
//here you are creating a tempList so after you fill in the values in tempList
//the tempList is to become a part of Employee list[MAXSIZE];
}
}
and how do you fill in the values? You do this using your constructor and maintaining the count
EmployeeList::EmployeeList(istream& in) {
//here...
}
You could start off by figuring out how to read in input. The approach, which is likely incomplete, that I would take is this:
EmployeeList::EmployeeList(istream& in) {
count = 0;
read(in); // delegate it to avoid duplication
}
void EmployeeList::read(istream& in) {
Employee tempList;
while (in >> tempList && count < MAXSIZE) {
list[count] = tempList;
++count;
}
}
You will need to overload operator>> for Employee class for this to work.
Here is how I would write this, without the skeleton constraint. Feel free to adapt to your assignment requirements.
Source: http://www.ideone.com/R9EeF
Iostreams are hard to master. You have to read about std::getline, the std::ios flags and stringstreams to understand how to parse an employee list with them.
I prefer giving you a working template (that you cannot use for your assignment since I don't make use of the skeleton at all), since there is a lot to say about iostreams.
Also feel free to ask questions, so that I can enhance my answer with your actual problems.