MultiMap not Printing List - c++

I am having 2 issues with my code.
The 1st issue is that my multimap is not printing, and I don't know why.
The 2nd issue is that I don't know how to create a function to search and find a specific item in my multimap.
You can change as much of the code as you want, but I need to keep the class or change it to a struct.
#include<iostream>
#include<string>
#include<iterator>
#include<map>
#include<algorithm>
#include<iomanip>
using namespace std;
class SongNode {
public:
string title;
string artist;
float rating;
};
//Constants
#define INFINITE_LOOP 1
#define LEFT_JUSTIFIED 30
//Prototypes
void sortByArtist(multimap<string, SongNode>& newSongNode);
void sortByRating(multimap<string, SongNode>& newSongNode);
//FUNCTION : void sortByArtist
//PARAMETER : multimap<string, SongNode>&newSongNode
//RETURN : void
//DESCRIPTION : This function will sort the multimap by the artist of the song
void sortByArtist(multimap<string, SongNode>&newSongNode) {
multimap<string, SongNode>temp;
for (auto i = newSongNode.begin(); i != newSongNode.end(); i++)
temp.insert(pair<string, SongNode>(i->second.artist, i->second));
newSongNode.clear();
for (auto i = temp.begin(); i != temp.end(); i++)
newSongNode.insert(pair<string, SongNode>(i->second.artist, i->second));
temp.clear();
}
//FUNCTION : void sortByRating
//PARAMETER : (multimap<string, SongNode>& newSongNode
//RETURN : void
//DESCRIPTION : This function will sort the multimap by the rating.
void sortByRating(multimap<string, SongNode>& newSongNode) {
multimap<float, SongNode, greater<int>> temp;
for (auto i = newSongNode.begin(); i != newSongNode.end(); i++)
temp.insert(pair<int, SongNode>(i->second.rating, i->second));
newSongNode.clear();
for (auto i = temp.begin(); i != temp.end(); i++)
newSongNode.insert(pair<string, SongNode>(" ", i->second));
temp.clear();
}
int main() {
multimap<string, SongNode> songList;
multimap<string, SongNode>::iterator itr;
string title;
string artist;
int rating;
SongNode* newSongNode = new SongNode;
cout << "Please enter a title artist and rating\n";
while (INFINITE_LOOP) {
cout << "Title: ";
cin >> title;
if (title == ".") {
break;
}
cout << "Artist: ";
cin >> artist;
cout << "Rating: ";
cin >> rating;
//Error check for rating
while (INFINITE_LOOP) {
if (rating < 1) {
cout << "The rating you have entered is less then 1\n";
cout << "Rating: ";
cin >> rating;
break;
}
else if (rating > 5) {
cout << "The rating you have to enterd is greater then 5\n";
cout << "Rating: ";
cin >> rating;
break;
}
else
break;
}
SongNode* newNode = new SongNode;
newNode->title = title;
newNode->artist = artist;
newNode->rating = rating;
songList.insert(pair<string, SongNode>(title, *newSongNode));
}
//display the two lists here.
cout << "Artist Sorted List\n";
sortByArtist(songList);
for (itr = songList.begin(); itr != songList.end(); ++itr) {
cout << "Title" << left << setw(LEFT_JUSTIFIED) << itr->second.title;
cout << "Artist" << left << setw(LEFT_JUSTIFIED) << itr->second.artist;
cout << "Rating" << left << setw(LEFT_JUSTIFIED) << itr->second.rating<<endl;
}
cout << "\n";
cout << "Rating Sorted List\n";
sortByRating(songList);
delete newSongNode;
return 0;
}

First of all, you have two variables with similar names, and you definitely misuse them:
SongNode* newSongNode = new SongNode;
// ...
SongNode* newNode = new SongNode;
newNode->title = title;
newNode->artist = artist;
newNode->rating = rating;
songList.insert(pair<string, SongNode>(title, *newSongNode));
You are initializing the newNode but inserting the newSongNode. The values are initialized with empty strings, so that may explain no printing.
As for "searching in a multimap" be more specific in what your problem is.

You are not populating the songList with the SongNode objects that you fill with data. You have an extra SongNode that has no data in it, which is the only object you are putting into the songList. So there is nothing to print.
Try this instead:
#include <iostream>
#include <string>
#include <iterator>
#include <map>
#include <algorithm>
#include <iomanip>
#include <limits>
using namespace std;
struct SongNode {
string title;
string artist;
float rating;
};
//Constants
#define INFINITE_LOOP 1
#define LEFT_JUSTIFIED 30
//Prototypes
void sortByArtist(multimap<string, SongNode>& newSongNode);
void sortByRating(multimap<string, SongNode>& newSongNode);
//FUNCTION : void sortByArtist
//PARAMETER : multimap<string, SongNode>&newSongNode
//RETURN : void
//DESCRIPTION : This function will sort the multimap by the artist of the song
void sortByArtist(multimap<string, SongNode> &newSongNode) {
multimap<string, SongNode> temp;
for (auto &elem : newSongNode)
temp.insert(make_pair(elem.second.artist, elem.second));
newSongNode.clear();
for (auto &elem : temp)
newSongNode.insert(make_pair(elem.second.artist, elem.second));
}
//FUNCTION : void sortByRating
//PARAMETER : (multimap<string, SongNode>& newSongNode
//RETURN : void
//DESCRIPTION : This function will sort the multimap by the rating.
void sortByRating(multimap<string, SongNode>& newSongNode) {
multimap<float, SongNode, greater<int>> temp;
for (auto &elem : newSongNode)
temp.insert(make_pair(elem.second.rating, elem.second));
newSongNode.clear();
for (auto &elem : temp)
newSongNode.insert(make_pair(" ", elem.second));
}
int main() {
multimap<string, SongNode> songList;
string title, artist;
float rating;
cout << "Please enter a title artist and rating\n";
while (INFINITE_LOOP) {
cout << "Title: ";
cin >> title;
if (title == ".") {
break;
}
cout << "Artist: ";
cin >> artist;
cout << "Rating: ";
cin >> rating;
//Error check for rating
while (INFINITE_LOOP) {
if (!cin) {
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "The rating you have entered is invalid\n";
}
else if (rating < 1.0f) {
cout << "The rating you have entered is less then 1\n";
}
else if (rating > 5.0f) {
cout << "The rating you have to entered is greater then 5\n";
}
else
break;
cout << "Rating: ";
cin >> rating;
}
SongNode newNode;
newNode.title = title;
newNode.artist = artist;
newNode.rating = rating;
songList.insert(make_pair(title, newNode));
}
//display the two lists here.
cout << "Artist Sorted List\n";
sortByArtist(songList);
for (auto &elem : songList) {
cout << "Title" << left << setw(LEFT_JUSTIFIED) << elem.second.title;
cout << "Artist" << left << setw(LEFT_JUSTIFIED) << elem.second.artist;
cout << "Rating" << left << setw(LEFT_JUSTIFIED) << elem.second.rating << endl;
}
cout << "\n";
cout << "Rating Sorted List\n";
sortByRating(songList);
for (auto &elem : songList) {
cout << "Title" << left << setw(LEFT_JUSTIFIED) << elem.second.title;
cout << "Artist" << left << setw(LEFT_JUSTIFIED) << elem.second.artist;
cout << "Rating" << left << setw(LEFT_JUSTIFIED) << elem.second.rating << endl;
}
cout << "\n";
return 0;
}

Related

What's the condition that i can use to print out all the strings that meet the conditions

I want to print out all the books that have "childrensbook" type at the end
for example :
bookname : tower
booktype : drama
bookname : flower
booktype : childrensbook
bookname : sun
booktype : childrensbook
...
...
...
The children books are :
flower
sun
#include <iostream>
#include <string.h>
using namespace std;
class Books
{
public:
string name;
string type;
void getdetails() {
cout <<"enter book's name : ";
cin >> name;
cout <<"enter book's type : ";
cin >> type;
cout << endl;
}
};
int main() {
string name2[19];
string type2[19];
string test = "childrensbook";
Books book1;
for (int i=0;i<5;i++)
{
cout << "Book " << (i+1) << " info : " << endl;
book1.getdetails();
name2[i] == book1.name;
type2[i] == book1.type;
if(test == book1.type)
{
/*HERE I WANT TO SAVE THE BOOKS THAT ACTUALLY HAVE
"childrensbook" TYPE AND PRINT THEM OUT */
}
}
return 0;
}
Try this:
#include <iostream>
#include <string>
using namespace std;
class Book
{
public:
string name;
string type;
void getdetails() {
cout << "enter book's name : ";
getline(cin, name);
cout << "enter book's type : ";
getline(cin, type);
}
};
int main() {
string test = "childrensbook";
Book books[5];
for (int i = 0; i < 5; i++)
{
cout << "Book " << (i+1) << " info : " << endl;
books[i].getdetails();
}
for (int i = 0; i < 5; i++)
{
if (books[i].type == test)
{
cout << "bookname : " << books[i].name << endl;
}
}
return 0;
}
Online demo

vector pointers and retrieving data

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)

cout doesn't seem to work correctly within vector iterator C++

I am currently working on the assignment where I need to iterate through some student records. Each record has reg. number, name, and 0 to multiple module names with marks respectively.
I have a Student class and a Main class.
In the main class there's a function to iterate through a vector of Students and print the average grade.
Function to print average grades as well as names.
void aboveGiven(vector<Student> &students, float given) {
vector<Student>::iterator it;
for(it = students.begin(); it != students.end(); it++) {
if(it -> getAverageMark() >= given) {
cout << it->getName() << " " << setprecision(2) << it->getAverageMark() << endl;
}
}
}
Function to calculate average grade. "Given" parameter is the input used to define above what average to display the records. (in this case it is 70 meaning all the records with average above 70 have to be printed)
float Student::getAverageMark() const
{
if (marks.size() == 0)
return 0;
int count;
float sum;
map<string, float>::const_iterator it;
for (it = marks.begin(); it != marks.end(); ++it, ++count) {
sum += it->second;
}
return sum / count;
}
The massive problem I have is weird behaviour of cout where it prints nothing if I pass 60 or above as a "Given" parameter.
However the following code:
void aboveGiven(vector<Student> &students, float given) {
vector<Student>::iterator it;
for(it = students.begin(); it != students.end(); it++) {
cout << "a" << endl;
if(it -> getAverageMark() >= given) {
cout << it->getName() << " " << setprecision(2) << it->getAverageMark() << endl;
}
}
}
with only difference of line cout << "a" << endl;gives me following output:
a
a
a
Lisa Simpson 88.03
a
Homer Simpson 99.90
a
a
Wayne Rooney 75.45
a
a
a
a
Where 'a' corresponds to all the records with average grade below 70 and, as we can see all the records with average grade above 70 are now printed well.
Sometimes, when using different parameters for cout, only some of the outputs would be actually displayed but not all.
I am new to C++ and still am very confused with references and pointers, so I suspect there might be a problem with them. Otherwise could this be an issue with IDE ( I am using CLion which supports C++11).
I am sorry if this is not informative enough, have never posted anything here before. If you need any additional information please feel free to ask, I will post it.
classes just in case:
Student.cpp
using namespace std;
#include "Student.h"
#include <iostream>
Student::Student(const string& name, int regNo)
: Person(name)
{
this->name = name;
this->regNo = regNo;
this->marks = marks;
}
int Student::getRegNo() const
{
return regNo;
}
void Student::addMark(const string& module, float mark)
{
marks[module] = mark;
}
float Student::getMark(const string& module) throw(NoMarkException)
{
if (marks.find(module) == marks.end()) {
throw NoMarkException();
}
return marks[module];
}
float Student::getAverageMark() const
{
if (marks.size() == 0)
return 0;
int count;
float sum;
map<string, float>::const_iterator it;
for (it = marks.begin(); it != marks.end(); ++it, ++count) {
sum += it->second;
}
cout << fixed;
return sum / count;
}
And main: (at the moment it is really bad styled, sorry)
using namespace std;
#include <iostream>
#include <fstream>
#include <sstream>
#include "Student.h"
#include <vector>
#include <iomanip>
void aboveGiven(vector<Student>& students, float given)
{
vector<Student>::iterator it;
for (it = students.begin(); it != students.end(); it++) {
cout << "a" << endl;
if (it->getAverageMark() >= given) {
cout << it->getName() << " " << setprecision(2) << it - > getAverageMark() << endl;
}
}
}
int main()
{
char studentFileName[30];
char marksFileName[30];
vector<Student> students;
cout << "Enter the name of a file with Students: " << endl;
cin >> studentFileName;
ifstream studentFile;
string line;
studentFile.open(studentFileName, ios::in);
if (studentFile.is_open()) {
while (getline(studentFile, line)) {
istringstream iss(line);
int regn;
string firstName, lastName;
iss >> regn >> firstName >> lastName;
students.push_back(Student(firstName + " " + lastName, regn));
}
studentFile.close();
}
else {
cout << "Failed to open: " << studentFileName << endl;
}
cout << "Enter the name of a file with Marks: " << endl;
cin >> marksFileName;
ifstream marksFile;
string ln;
marksFile.open(marksFileName, ios::in);
if (marksFile.is_open()) {
while (getline(marksFile, ln)) {
int regn;
string module;
float mark;
bool studentFound = false;
istringstream iss(ln);
iss >> regn >> module >> mark;
for (auto& student : students) {
if (student.getRegNo() == regn) {
student.addMark(module, mark);
studentFound = true;
}
}
if (!studentFound) {
cout << "Student with Registration Number " << regn << was not found." << endl;
}
}
marksFile.close();
}
else {
cout << "Failed to open: " << marksFileName << endl;
}
for (auto& student : students) {
map<string, float> tempMap = student.getMarks();
map<string, float>::iterator it;
cout << setw(20) << student.getName() << ": ";
if (tempMap.size() == 0) {
cout << "N/A";
}
else {
for (it = tempMap.begin(); it != tempMap.end(); it++) {
cout << setw(5) << it->first << '(' << it->second << "); ";
}
}
cout << endl;
}
aboveGiven(students, 70);
}
Thanks in advance for your help!
You didn't initialize int sum and int count in Student::getAverageMark. Then no one knows what could they be. They must be int sum = 0; and int count = 0;

convert function into member function?

I'm new here and I'm looking for help with a program written in c++.
I want to convert following functions that are not in a class nor in main() of my program
void PrintInventory(vector<Item*> inventory);
vector<Item*> AddItemToInventory(vector<Item*> inventory);
vector<Item*> UpdateItemQtyInInventory(vector<Item*> inventory);
vector<Item*> RemoveItemFromInventory(vector<Item*> inventory);
into public function members of a class Inventory that have no parameters and return nothing.
I've been working on that for 4 days now and just can't figure out how I'm supposed to change these functions to be void and have no parameter without destroying the whole program...
If I go exactly by what the instruction say which is to make a void/no parameters out of the four functions, I would get something like:
class Inventory
{
public:
void PrintInventory() {}
void AddItemToInventory() {}
void UpdateItemQtyInInventory() {}
void RemoveItemFromInventory() {}
private:
vector<Item*> inventory;
};
Please give me a hint. I feel like the solution must be simple but I've been completely stuck for days.
Thanks for your help.
EDIT:
I'm still getting a bunch of errors and think I need to say a bit more about my code:
I have a base class Item and two derived classes Produce and Book. Then I have four function calls:
// Print all items in the inventory
void PrintInventory(vector<Item*> inventory);
// Dialogue to create a new item, then add that item to the inventory
vector<Item*> AddItemToInventory(vector<Item*> inventory);
// Dialogue to update the quantity of an item, then update that item in the inventory
vector<Item*> UpdateItemQtyInInventory(vector<Item*> inventory);
// Dialogue to remove a specific item, then remove that specific item from the inventory
vector<Item*> RemoveItemFromInventory(vector<Item*> inventory);
Next comes the main and my class Inventory that now has four converted functions with no return and no parameters that were not originally inside the class Inventory and had parameters/return before.
Here is the whole code, I think it's better to understand this way:
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <cstring>
using namespace std;
class Item {
public:
void SetName(string nm)
{
name = nm;
};
void SetQuantity(int qnty)
{
quantity = qnty;
};
void SetPrice(int prcInDllrs) //step1
{
priceInDollars = prcInDllrs; //step1
};
virtual void Print()
{
cout << name << " " << quantity << endl;
};
virtual ~Item()
{
return;
};
protected:
string name;
int quantity;
int priceInDollars; //step1
};
class Produce : public Item { // Derived from Item class
public:
void SetExpiration(string expir)
{
expiration = expir;
};
void Print()
{
cout << name << " x" << quantity
<< " for $" << priceInDollars //step1
<< " (Expires: " << expiration << ")"
<< endl;
};
private:
string expiration;
};
//step 2 add derived class Book
class Book : public Item { // Derived from Item class
public:
void SetAuthor(string authr) //create author function with parameter
{
author = authr;
};
void Print()
{
cout << name << " x" << quantity
<< " for $" << priceInDollars //step1
<< " (Author: " << author << ")"
<< endl;
};
private:
string author;
};
// Print all items in the inventory
void PrintInventory(vector<Item*> inventory);
// Dialogue to create a new item, then add that item to the inventory
vector<Item*> AddItemToInventory(vector<Item*> inventory);
// Dialogue to update the quantity of an item, then update that item in the inventory
vector<Item*> UpdateItemQtyInInventory(vector<Item*> inventory);
// Dialogue to remove a specific item, then remove that specific item from the inventory
vector<Item*> RemoveItemFromInventory(vector<Item*> inventory);
int main() {
vector<Item*> inventory;
string usrInptOptn = "default";
while (true) {
// Get user choice
cout << "\nEnter (p)rint, (a)dd, (u)pdate, (r)emove, or (q)uit: ";
getline(cin, usrInptOptn);
// Process user choice
if (usrInptOptn.size() == 0) {
continue;
}
else if (usrInptOptn.at(0) == 'p') {
PrintInventory(inventory);
}
else if (usrInptOptn.at(0) == 'a') {
inventory = AddItemToInventory(inventory);
}
else if (usrInptOptn.at(0) == 'u') {
inventory = UpdateItemQtyInInventory(inventory);
}
else if (usrInptOptn.at(0) == 'r') {
inventory = RemoveItemFromInventory(inventory);
}
else if (usrInptOptn.at(0) == 'q') {
cout << "\nGood bye." << endl;
break;
}
}
return 0;
}
class Inventory {
public:
void PrintInventory() {
unsigned int i = 0;
if (inventory.size() == 0) {
cout << "No items to print." << endl;
}
else {
for (i = 0; i<inventory.size(); ++i) {
cout << i << " - ";
inventory.at(i)->Print();
}
};
}
void AddItemToInventory() {
Produce* prdc;
Book* book; //create new pointer object of class book
string usrInptName = "";
string usrInptQntyStr = "";
istringstream inSS;
int usrInptQnty = 0;
string usrInptExpr = "";
int usrInptPrc = 0; //step1
string usrInptAuthr = ""; //declare variable
string usrInptBookName = "";
int usrInptQntyBook = 0;
string usrInptQntyBookStr = "";
string usrInptChoice = " ";
//loop user choice and ask again if choice is not valid
do {
cout << "Enter choice of adding (b)ook or (p)roduce: ";
getline(cin, usrInptChoice);
if (usrInptChoice != "b" && usrInptChoice != "p") {
cout << "Invalid Choice" << endl;
}
} while (usrInptChoice != "b" && usrInptChoice != "p");
//only ask for inventory type accoring to user input p or b
if (usrInptChoice == "p") {
cout << "Enter name of new produce: ";
getline(cin, usrInptName);
cout << "Enter quantity: ";
getline(cin, usrInptQntyStr);
inSS.str(usrInptQntyStr);
inSS >> usrInptQnty;
inSS.clear();
cout << "Enter expiration date: ";
getline(cin, usrInptExpr);
cout << "Enter the price per item : $"; //step1
cin >> usrInptPrc; //step1
prdc = new Produce;
prdc->SetName(usrInptName);
prdc->SetQuantity(usrInptQnty);
prdc->SetExpiration(usrInptExpr);
prdc->SetPrice(usrInptPrc);
inventory.push_back(prdc);
}
if (usrInptChoice == "b") {
cout << "Enter name of new book: ";
getline(cin, usrInptBookName);
cout << "Enter quantity: ";
getline(cin, usrInptQntyBookStr);
inSS.str(usrInptQntyBookStr);
inSS >> usrInptQntyBook;
inSS.clear();
cout << "Enter author: ";
getline(cin, usrInptAuthr);
cout << "Enter the price per item : $"; //step1
cin >> usrInptPrc; //step1
book = new Book;
book->SetName(usrInptBookName);
book->SetQuantity(usrInptQntyBook);
book->SetAuthor(usrInptAuthr);
book->SetPrice(usrInptPrc);
inventory.push_back(book);
};
}
void UpdateItemQtyInInventory() {
string usrIndexChoiceStr = "";
unsigned int usrIndexChoice = 0;
istringstream inSS;
string usrInptQntyStr = "";
int usrInptQnty = 0;
if (inventory.size() == 0) {
cout << "No items to update." << endl;
}
else {
PrintInventory();
do {
cout << "Update which item #: ";
getline(cin, usrIndexChoiceStr);
inSS.str(usrIndexChoiceStr);
inSS >> usrIndexChoice;
inSS.clear();
} while (!(usrIndexChoice < inventory.size()));
cout << "Enter new quantity: ";
getline(cin, usrInptQntyStr);
inSS.str(usrInptQntyStr);
inSS >> usrInptQnty;
inSS.clear();
inventory.at(usrIndexChoice)->SetQuantity(usrInptQnty);
};
}
void RemoveItemFromInventory() {
istringstream inSS;
string usrIndexChoiceStr = "";
unsigned int usrIndexChoice = 0;
string usrInptQntyStr = "";
if (inventory.size() == 0) {
cout << "No items to remove." << endl;
}
else {
PrintInventory();
do {
cout << "Remove which item #: ";
getline(cin, usrIndexChoiceStr);
inSS.str(usrIndexChoiceStr);
inSS >> usrIndexChoice;
inSS.clear();
} while (!(usrIndexChoice < inventory.size()));
inventory.erase(inventory.begin() + usrIndexChoice);
};
}
private:
vector<Item*> inventory;
};
I don't get any compilation errors in Visual Studio but when I try to build, there are 5 errors. Compiling the program in Geany gives me no errors either but when I build, it says:
undefined reference to `PrintInventory(std::vector<Item*, std::allocator<Item*> >)'
undefined reference to `AddItemToInventory(std::vector<Item*, std::allocator<Item*> >)'
undefined reference to `UpdateItemQtyInInventory(std::vector<Item*, std::allocator<Item*> >)'
undefined reference to `RemoveItemFromInventory(std::vector<Item*, std::allocator<Item*> >)'
collect2.exe: error: ld returned 1 exit status
Compilation failed.
I feel like I'm missing some basic, simple thing but I just can't figure it out. The instruction is confusing to me when it says I have to convert the functions PrintInventory, AddItemToInventory, UpdateItemQtyInInventory,
and RemoveItemFromInventory into void/no parameters but which functions does it refer to? The four definition lines? The actual functions? Both? And what about the main and the other classes? Wouldn't I need to change things there as well?
I believe your code conversion is correct. Since 'Inventory vector' is a a member variable it can be accessed by all the other member function and can also be manipulated. This removes the requirement for passing vector as argument.
Now for returning the vector I would suggest adding a new "GetInventory()" method which returns the vector or take a reference to pass the vector.
Hope it helps.
Thanks to WhozCraig, my problem has been solved:
"The class definition of Inventory has to come before main() somehow. Move it above main() and it should work."
Basic testing:
Note, there are no pointers in here
void test()
{
class T_item
{
public:
string name;
int quantity;
int priceInDollars;
};
vector<T_item> inventory;
T_item temp;
//add item:
temp.name = "name1";
temp.quantity = 1;
temp.priceInDollars = 1;
inventory.push_back(temp);
temp.name = "name2";
temp.quantity = 2;
temp.priceInDollars = 2;
inventory.push_back(temp);
cout << "print:\n";
for each(T_item item in inventory)
{
cout << item.name << endl;
cout << item.quantity << endl;
cout << item.priceInDollars << endl << endl;
}
//modify item at index 1:
inventory[1].name = "modified";
//delete item at index 0:
inventory.erase(inventory.begin() + 0);
cout << "print again:\n";
for each(T_item item in inventory)
{
cout << item.name << endl;
cout << item.quantity << endl;
cout << item.priceInDollars << endl << endl;
}
}
int main()
{
test();
return 0;
}

c++ trouble with either RTTI or binary file io

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)?