I am completing a hotel reservation form using C++ language. I keep getting no operator error for fin !=0. How can I address this error? Here is the actual coding...
void Hotel::show_room_record()
{
cout << "R.Num" << setw(10) << "R.Stat" << setw(10) << "Category" << setw(10) << "Rent\n";
ifstream fin("room.dat", ios::in);
for (int p = 0; fin != 0; p = p + 15)
{
fin.seekg(p);
fin >> room_no;
fin >> room_status;
fin >> category;
fin >> rent;
cout << room_no << setw(10) << room_status << setw(10) << category << setw(10) << rent << "\n";
}
fin.close();
}
You can't compare fin with 0, fin wont return the next input.
First store the input in a variable, then compare it.
For your case, you probably want to check if the next character is a '0', or even a '\0'.
Try using this:
http://www.cplusplus.com/reference/istream/istream/peek/
Your condition becomes (assuming you want '\0'):
fin.peek() != 0
You cannot test fin != 0. fin isn't a number, to testing for equality with 0 makes about as much sense as testing what kind of orange an apple is. You can test that fin is still readable though with a simple fin by taking advantage of operator bool, but that's tricky because the test for is readable will be made before reading. You can't test for failure before you have a chance to fail and that leaves open the possibility that the last reads failed and were not checked for validity.
Instead of trying to fix this, I'm going to go all X-Y on you here and suggest something completely different.
Define a structure
struct room
{
int room_no;
string room_status;
string category;
int rent; // could be a float. Don't care much for this example
// that said, watch out for rounding errors when dealing with floats
};
Create a function that makes it really easy to read into this structure
std::istream & operator>>(std::istream & in,
room & inroom)
{
in >> inroom.room_no >> inroom.room_status >> inroom.category >> inroom.rent;
return in;
}
Create a function that makes it really easy to write this structure
std::ostream & operator<<(std::ostream & out,
const room & outroom)
{
out << outroom.room_no << setw(10) << outroom.room_status <<
setw(10) << outroom.category << setw(10) << outroom.rent;
return out;
}
Make a std::vector of the above structure a member of the Hotel class
std::vector<room> rooms;
Read the file into it
room temp;
while (in >> temp)
{
rooms.push_back(temp);
}
Now the hotel knows the status of all the rooms without having to keep looking at the file. This makes printing easy.
for(room & r: rooms)
{
cout << r << '\n';
}
It makes finding any room a simple traversal of rooms
for(room & r: rooms)
{
if (r.whatever == desiredwhatever)
{
return r;
}
}
and every now and then you rewrite the file if a room was changed.
std::ostream outfile("path to file goes here");
for(room & r: rooms)
{
if (!(outfile << r << '\n'))
{
//handle error
}
}
All of these things you probably have to do anyway. The only downside is if you are not allowed to use std::vector. In that case you either write a simple vector substitute or use an array and pray it never overflows.
Related
Problem Sample Run
Problem Description (1)
Problem Description (2)
The link above is an image of what the program should do once reading in a text file and outputting it correctly to another file. The two other links are descriptions of the problem itself. My problem is that while most of the logic works, when it comes to printing it out, it skips the first number in the input file. For example, if the input file was:
1 10000
2 5000
3 150000
Right now the output in the file prints:
Store 2: *
Store 3: ***
Again, the image provides a better example of what is to happen. The code should work for any text file given, no matter for the order of the numbers: (ex: 50 10000, 5 5000, so on).
I am not sure why this happening. I'm attaching my code for reference below. I would like to apologize in advance for the lack of comments right now, I'm trying to fix the error first. I have narrowed the error down to the while loop in the main function however. Second, I'm somewhat of a beginner, so please excuse any silly mistakes I've made or if I did things in a more inefficient way. Another note is that I can't change the signatures for the functions, and I have to check the values if they are valid in the readFile() function. I also cannot use arrays, or the pause command, or break and continue. Third, I am pretty new to stack overflow so please do excuse any errors I make. Thank you!
As of now, the code that is commented out, is code I don't plan to use, but if there is a way to achieve the goal using that code and staying within the guidelines, please do let me know. This error is quite a frustrating one! Also, I do have some more error to fix afterwards, but those are minor ones I can fix later. I want to fix this error first. Thank you!
#include <iostream>
#include <iomanip>
#include <cmath>
#include <fstream>
using namespace std;
bool readFile(ifstream&, long long int&, unsigned int&);
void display(ofstream&, long long int, unsigned int);
int main()
{
ifstream inputFile;
ofstream outputFile;
string fileName;
long long int salesData;
unsigned int storeNumber;
cout << "Enter input file name" << endl;
cin >> fileName;
inputFile.open(fileName);
bool fileRead = readFile(inputFile, salesData, storeNumber);
if(fileRead)//inputFile >> storeNumber >> salesData)
{
outputFile.open("saleschart.txt");
outputFile << "SALES BAR CHART" << endl;
outputFile << "(Each * equals 5,000 dollars)" << endl;
while(inputFile >> storeNumber >> salesData)
{
display(outputFile, salesData, storeNumber);
/*
if(storeNumber < 1 || storeNumber > 99)
{
cout << "The store number " << storeNumber << " is not valid" << endl;
}
if(salesData < 0)
{
cout << "The sales value for store " << storeNumber << " is negative" << endl;
}
*/
}
inputFile.close();
outputFile.close();
}
return 0;
/*
while(inputFile >> storeNumber >> salesData)
{
int counter = 1;
for(int i = 1; i <= counter; i++)
{
counter++;
bool fileRead = readFile(inputFile, salesData, storeNumber);
if(fileRead)
{
outputFile.open("saleschart.txt");
outputFile << "SALES BAR CHART" << endl;
outputFile << "(Each * equals 5,000 dollars)" << endl;
display(outputFile, salesData, storeNumber);
}
}
*/
}
bool readFile(ifstream& inputFile, long long int& salesData, unsigned int& storeNumber)
{
if(inputFile)
{
inputFile >> storeNumber >> salesData;
if(storeNumber == NULL)
{
cout << "The file was empty" << endl;
return false;
}
if(storeNumber < 1 || storeNumber > 99)
cout << "The store number " << storeNumber << " is not valid" << endl;
if(salesData < 0)
cout << "The sales value for store " << storeNumber << " is negative" << endl;
else
return true;
}
else
{
cout << "File \"sales.txt\" could not be opened" << endl;
return false;
}
return false;
/*
if(inputFile.eof())
return false;
else
{
inputFile >> storeNumber >> salesData;
return true;
}
*/
}
void display(ofstream& outputFile, long long int salesData, unsigned int storeNumber)
{
outputFile << left << setw(6) << "Store" << right << setw(2) << storeNumber << ": ";
cout<<storeNumber; //DEBUG
for(int i = 0; i < (salesData/5000); i++)
{
outputFile << left << "*";
}
outputFile << endl;
}
It's skipping the first numbers because you read them (and the don't save them) in the function readFile. It's got nothing to do with your while loop which is completely correct. But you can't read the same numbers twice, and you have already read the first numbers by the time you get to your while loop.
Not sure what you are expecting from the function readFile, it looks like you tried to read the file in a separate function but then abandoned it. If you just delete the readFile function your code should work.
OK reading your question again I see that are required to use the readFile function. If that is the case then the correct thing to do is delete the current contents of the readFile function and move the while loop into the readFile function.
You have a few problems, the main is that the readFile function reads the first two values, and then you discard the data it has read.
This discarded data will never be written to the output file.
Also in the readFile function you have the comparison storeNumber == NULL which might be a check if the input failed, but that's not how to do that.
First of all because C++ doesn't have null values, NULL is an old C-compatibility constant for a null pointer.
Secondly, you already have the correct check in the loop where you read the remaining data, where you use the whole input expression inputFile >> storeNumber >> salesData as the condition.
Now to put it all together, you don't need the readFile function at all, instead all you need is the reading loop:
outputFile.open("saleschart.txt");
if (!outputFile)
{
// Failed to open the output file
return 1;
}
inputFile.open(fileName);
while(inputFile >> storeNumber >> salesData)
{
display(outputFile, salesData, storeNumber);
}
How do I set up a loop to read in file data until eof is reached?
Basically, I have a data file with student data, and for each student there is quiz grades, test grades, lab grades, etc.
I have a function that gives the values as letter grades.
My issue is to set up the loop to compute each function 4 times for each student. My loop code so far uses a counter loop, but I'm supposed to turn it into an eof loop instead.
My code below ends when there is no more data to read.
int main()
{
int counters = 1;
char lab;
char assgniment_score;
char quiz_score;
char test_score;
float final_total_average;
myfile.open("infile.txt");
while (counters <= 20) {
lab = Compute_lab_grade();
assgniment_score = Compute_Assignment_grade();
quiz_score = Compute_Quiz_grade();
test_score = Compute_test_grade();
final_total_average = (10 * (total(quiz_score))
+ (25 * (total(assgniment_score)))
+ (30 * (total(lab))) + (35 * total(test_score))) / 100;
cout << "Student " << counters << endl;
cout << "Student Lab grade is : " << lab << endl;
cout << "Student Assignment grade is : " << assgniment_score << endl;
cout << "Student Quiz grade is : " << quiz_score << endl;
cout << "Student Exam grade is : " << test_score << endl;
cout << "Student Final grade is : " << final_average_score(final_total_average) << endl << endl;
counters++;
}
}
The structure of the given data looks like this:
Rational for answer: OP is headed in many wrong directions all at once and I think a few of them can be headed off with one good example.
Problem 1: EOF loop is a myth. Read more here: Why is iostream::eof inside a loop condition considered wrong?
Problem 2: using char to represent numbers. Technically char is an integer type, but it is most commonly associated with a single character and its input/output routines are overloaded accordingly. Eg. if given input "1234" std::cin >> a_char; will result in char a_char containing the character '1', but std::cin >> an_int; will result in int an_int containing the the number 1234. In addition using a character to represent a number can often lead to confusion for thew reader who may misinterpret what your code is supposed to do. You can do it and sometimes it is the appropriate choice, but this time it doesn't make much sense.
Problem 3 Scattershot and unchecked IO. It's generally best to read in everything you want and then, if the input is good, make a decision on all of it all at once. If a student's record is not complete without 27 integers, read all 27 integers and check that each and every one read correctly. If you can't read them all, that's an error. If some are not integers, that's an error. If you have an error, the student is not a valid input and should either be discarded or investigated more closely.
Problem 4: Not using a data structure to contain associated data. A student is represented by a bunch of information. It is convenient to package that information with the methods by which the information can be accessed and manipulated. Read up on encapsulation.
Minor nag: Why is "using namespace std" considered bad practice?
So here we go:
#include <iostream>
#include <fstream>
#include <sstream>
// using namespace std; avoid using this. Can be very dangerous to the unwary.
// container class to aggregate student stats and provide manipulators to read
// and display a student
class Student
{
static int count; // only the students use the counter. No need for it to be global.
int student_number;
// int telegraphs your intent much better than char
// These variables are numbers, not characters and should be treated like them
int lab;
int assgniment_score;
int quiz_score;
int test_score;
float final_total_average;
public:
// simple input function. This is a bit too simple for OP, but should be
// enough for OP to get the idea.
friend std::istream & operator>>(std::istream & in, Student & student)
{
std::string line;
student.student_number = count ++;
if (std::getline(in, line))
{
std::stringstream stream(line);
if (stream >> student.lab
>> student.assgniment_score
>> student.quiz_score
>> student.test_score)
{ // if we read all the variables we needed
// divided by 4.0 because division of int by int will
// give an int, not a float.
student.final_total_average = (student.lab +
student.assgniment_score +
student.quiz_score +
student.test_score) / 4.0;
}
else
{ // failed to read. Mark stream bad.
in.setstate(std::istream::failbit);
}
}
return in;
}
// simple output function OP shouldn't have to change much here.
friend std::ostream & operator<<(std::ostream & out, Student & student)
{
//endl is line feed and IO flush very expensive, so use only
// when you absolutely need to flush the stream. This turns out to be
// almost enver.
out << "Student " << student.student_number << '\n'
<< "Student Lab grade is : " << student.lab << '\n'
<< "Student Assignment grade is : " << student.assgniment_score << '\n'
<< "Student Quiz grade is : " << student.quiz_score << '\n'
<< "Student Exam grade is : " << student.test_score << '\n'
<< "Student Final grade is : " << student.final_total_average << '\n';
return out;
}
};
// allocate storage for student counter
int Student::count = 1;
int main()
{
// create and open file. As with the counter, no need for it to be global
// because it can easily be passed by reference into functions that need it.
std::ifstream myfile("infile.txt");
Student student; // allocate a dummy student to read into and print
// because we have smart rules for reading in a student, this is easy.
while (myfile >> student) // read students until error or end of file
{
std::cout << student; // write the current student
}
}
I am trying to read data from a text file formatted similarly to this:
knife, object, 0
bag, object, 15
kitchen, room, 400
Into an array composed of structures. Here is what I have so far, but it only reads the first element then returns garbage.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
struct itemlist
{
string type;
string selltype;
int price;
int diditsell=0;
};
int main()
{
string filename;
cout << "Please enter a file name. " << endl;
cin >> filename;
ifstream in(filename);
itemlist c[100];
for (int i=0;i<100;i++)
{
in >> c[i].type >> c[i].selltype >> c[i].price;
cout << c[i].type << endl;
cout << c[i].selltype << endl;
cout << c[i].price << endl;
}
}
I have tried to find examples that specifically suit what I am trying to do but implementing them has not fixed the problem. Any help would be greatly appreciated.
The crux of the visible problem is that with
for (int i=0;i<100;i++)
the entire 100 element array will be printed out whether there was data in the file to be loaded into the array or not.
Probably the easiest way to do this is with a std::vector. It's a dynamically sized array. As you add to it it gets bigger so you don't have to worry about it overflowing. We'll get back to it at the end.
The next thing you have to do is make sure you're reading the file successfully. Streams can be tested to see if they are valid.
if (in)
{
cout << "in is good!" << endl;
}
and the >> operator returns a reference to the stream so you can
if (in >> data)
{
cout << "data is good!" << endl;
}
If the stream is still good after reading data, you know that at the very least the file read something into data that was of the correct type or could be converted into the correct type. You owe it to yourself to check the value read after reading it in to make sure the user didn't typo or go out of their way to crash the program. If you want to loop through a lot of stuff, like a file, you wind up with something like this:
while (in >> c[i].type >> c[i].selltype >> c[i].price)
If any of the reads failed the the stream will return false when tested and the loop will exit.
Looking at your source data you have spaces and commas to deal with. >> only knows how to deal with spaces unless you're going to do a lot of extra work. What you will read in is
knife,
object,
0
and we don't want the comma. Fortunately, it's the last character so dealing with it is easy. A C++11 std::string can be used like a stack and you can just pop the unwanted character off:
c[i].type.pop_back();
c[i].selltype.pop_back();
All together, this gives us a loop that looks like
ifstream in(filename);
itemlist c[100];
int i = 0;
while (in >> c[i].type >> c[i].selltype >> c[i].price)
{
c[i].type.pop_back();
c[i].selltype.pop_back();
cout << c[i].type << endl;
cout << c[i].selltype << endl;
cout << c[i].price << endl;
i++;
}
but this can overrun the end of the 100 element array, so we need to change the while loop slightly:
while (i < 100 && in >> c[i].type >> c[i].selltype >> c[i].price )
If i is greater than or equal to 100, the i < 100 case fails and the loop exits without even trying in >> c[i].type >> c[i].selltype >> c[i].price and writing into the non-existent array slot.
Remember to keep the value of i around because arrays are dumb. They don't know how full they are.
But with a vector you don't need i to count or to keep track of how full it is and you don't need to worry about overflowing the array until you run your computer out of RAM. What we do need is one temporary variable to read into and we're good to go.
vector<itemlist> c;
itemlist temp;
while (in >> temp.type >> temp.selltype >> temp.price)
{
temp.type.pop_back();
temp.selltype.pop_back();
cout << temp.type << endl;
cout << temp.selltype << endl;
cout << temp.price << endl;
c.push_back(temp);
}
I had the same problem.
A debug showed that it was reading the first array element but skipping to the second element and outputting the info. from the first element.
This was fixed by making it read the first element twice.
For example see below.
I had other input in the array for the player also.
After that line was added everything worked great.
I had to do that for every array that I read.
I looked at the text file it was reading from and sure enough
there is a blank line before the start of every array.
I do not know why the program writing the file did that.
I did not put a blank line before the array.
Note: Instead of having it read the first array element twice,
you could probably have it read a blank line instead.
for (int i = 0; i < PLAYER; i++)
{
getline(teamRosterIn, playerName[i]);
cout << playerName[i] << endl;
getline(teamRosterIn, playerName[i]);
cout << playerName[i] << endl;
}
I am writing a text-based Scrabble implementation for a college project.
The specification states that the user's position input must be read from single line, like this:
Coordinates of the word's first letter and orientation (<A – P> <1 – 15> <H ou V>): G 5 H
G 5 H is the user's input for that particular example. The order, as shown, must be char int char.
What is the best way to read the user's input?
cin >> row >> column >> orientation will cause crashes if the user screws up.
A getline and a subsequent string parser are a valid solution, but represent a bit of work.
Is there another, better, way to do this, that I am missing?
Thanks for your time!
getline and parsing doesn't necessarily have to add much work. Since you already know how to read (correct) data from a stream, just read a line with getline, then create an istringstream from the line and read from there.
The one thing I'd add would be that it might very well make sense to create a class to hold the data for a particular move, and overload operator>> for that class to read data for a move. A rough sketch would be something like this:
class move {
char row;
int column;
char orientation;
public:
friend std::istream &operator>>(std::istream &is, move &m);
};
std::istream &operator>>(std::istream &is, move &m) {
std::string temp;
std::getline(is, temp);
std::istringstream buffer(temp);
// Now we can parse data from buffer just like we could from another stream.
return is;
}
At least for the moment, I haven't included any error handling code. Depending on how picky you want to be, this can get a little tricky (e.g., if input from the stringstream fails, setting the fail bit in the original input stream).
Sorry, but getline and parsing the string are your best bet. However, you can make your system a little bit more reusable by creating a class to represent the input options and then overloading operator>> so that it uses getline and parses the string. That way, you don't have to repeat any of your parsing code.
I got something like this:
#include <iostream>
#include <limits>
#include <string>
using namespace std;
template<class T> T getValue(const string& name)
{
T ret;
while(!(cin >> ret))
{
// normally here you'd go into an infinite loop, but since you're going to ignore the rest of the line, you can ensure that you won't go into an infinite loop and you can re-ask the user to input the correct data
cout << "Invalid input for " << name << " please try again" << endl;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
return ret;
}
int main(void)
{
bool valid = false;
char row, orientation;
int column;
do {
cout << "Enter row, column, and orientation (<A-P> <1-15> <H to V>): " << endl;
row = getValue<char>("row");
column = getValue<int>("column");
orientation = getValue<char>("orientation");
if(row<'A' || row>'P')
cout << "Invalid row please enter A-P" << endl;
else if(column<1 || column>15)
cout << "Invalid column please enter 1-15" << endl;
else if(orientation<'H' || orientation>'V')
cout << "Invalid orientation please enter H-V" << endl;
else
valid = true;
} while(!valid);
cout << "Row: " << row << endl
<< "Column: " << column << endl
<< "Orientation: " << orientation << endl;
return 0;
}
Of course, if you enter something invalid like:
A B C
It would produce some potentially confusing problems. The first A would be successfully copied in row char variable. However since B is not numerical, it would ignore the remaining buffer, so you lose B and C. You get an error message that you entered an invalid input for column, but once you successfully enter a valid number, you would still have to enter a orientation again. So the user isn't clear on that point based on this application. You can make such modifications easily such that if you enter an invalid input, it would reask you to enter the whole thing.
Another suggestion is to input from the console, using one item at a time and apply an error checking:
char row;
bool is_valid = false;
while (!is_valid)
{
while (!(cin >> row))
{
cout << "Error reading row, please enter data again.\n";
}
row = toupper(row);
static const std::string valid_rows("ABCDEFGHIJKLMNO");
is_valid = valid_rows.find(row) != std::string::npos;
if (!is_valid)
{
cout << 'Row ' << row << ' is not a valid row letter, please re-enter.\n";
}
}
By reading one variable at a time, rather than all three at once, you can give the user earlier warning about error detection.
I'm trying to input a form of data validation in which when a user enter's a book's ISBN number, if it has already been stored then it will output an error message. However, I'm having trouble doing this. I'm not sure if I'm overloading the == operator correctly, and I'm not sure how to compare the vector values in the store_ISBN() function.
Here is the code:
#include "std_lib_facilities.h"
// Classes ---------------------------------------------------------------------
class Book{
public:
vector<Book> books; // stores book information
Book() {}; // constructor
friend ostream& operator<<(ostream& out, const Book& b);
bool operator==(const Book& d);
string what_title();
string what_author();
int what_copyright();
void store_ISBN();
void is_checkout();
private:
char check;
int ISBNfirst, ISBNsecond, ISBNthird;
char ISBNlast;
string title;
string author;
int copyright;
};
// Class Functions -------------------------------------------------------------
string Book::what_title()
{
cout << "Title: ";
getline(cin,title);
cout << endl;
return title;
}
string Book::what_author()
{
cout << "Author: ";
getline(cin,author);
cout << endl;
return author;
}
int Book::what_copyright()
{
cout << "Copyright Year: ";
cin >> copyright;
cout << endl;
return copyright;
}
void Book::store_ISBN()
{
bool test = false;
cout << "Enter ISBN number separated by spaces: ";
while(!test){
cin >> ISBNfirst >> ISBNsecond >> ISBNthird >> ISBNlast;
for(int i = 0; i < books.size(); ++i)
if(ISBNfirst == books[i]) cout << "test"; // no idea how to implement this line
if((ISBNfirst<0 || ISBNfirst>9) || (ISBNsecond<0 || ISBNsecond>9) || (ISBNthird<0 || ISBNthird>9))
error("Invalid entry.");
else if(!isdigit(ISBNlast) && !isalpha(ISBNlast))
error("Invalid entry.");
else test = true;}
cout << endl;
}
void Book::is_checkout()
{
bool test = false;
cout << "Checked out?(Y or N): ";
while(!test){
cin >> check;
if(check == 'Y') test = true;
else if(check == 'N') test = true;
else error("Invalid value.");}
cout << endl;
}
// Operator Overloading --------------------------------------------------------
bool Book::operator==(const Book& d){ // is this right???
if((ISBNfirst == d.ISBNfirst) && (ISBNsecond == d.ISBNsecond)
&& (ISBNthird == d.ISBNthird) && (ISBNlast == d.ISBNlast)) return true;
else return false;
}
ostream& operator<<(ostream& out, const Book& b){
out << "Title: " << b.title << endl;
out << "Author: " << b.author << endl;
out << "ISBN: " << b.ISBNfirst << "-" << b.ISBNsecond << "-" << b.ISBNthird << "-" << b.ISBNlast << endl;
out << endl;
return out;
}
// Main ------------------------------------------------------------------------
int main()
{
Book store;
string question;
while(true){
store.what_title();
store.what_author();
store.what_copyright();
store.store_ISBN();
store.is_checkout();
store.books.push_back(store);
cout << "Are you finished?(Y or N): ";
cin >> question;
if(question == "Y") break;
else if(question == "N"){
cout << endl;
cin.ignore();}
else error("Invalid value.");
}
cout << endl;
cout << "Books stored -\n" << endl;
for(int i = 0; i < store.books.size(); ++i)
cout << store.books[i];
keep_window_open();
}
Note that in the store_ISBN function I've only included testing for one variable since I don't want to type out the whole thing before I figure out how to do it.
As you can see each time a book passes through the loop in main, the data for that book is stored. I'm then able to output all the data input after the loop by overloading the << operator to print Title, Author, and ISBN. So I think I should be able to access that individual data in the vector to compare to the user input ISBN, but I don't know how. The parts that I am confused about have been commented as such.
I'm not sure quite what the user is expected to type for an ISBN.
Reading from a stream into an int will read digits up to a space, and convert the result to int (if all goes well, anyway). Reading into a char will store the char value. So at the moment you're validating than an ISBN looks like three single digits (0-9), and then the next char. That's not what I think an ISBN looks like.
Your operator== looks OK, although note that for a bool return value,
if (X) return true;
else return false;
can be replaced with
return X;
because conditionals are already of type bool.
After setting your ISBN values (and any other fields you plan to use in operator==, if it's not finished yet), the way to look for a matching book in the store is:
for(int i = 0; i < books.size(); ++i)
if(*this == books[i]) cout << "test";
In other words, look for a book equal to this book. Or you could use std::find from <algorithms>, although in this case it wouldn't really be any more concise.
By the way, it is unusual to use the same class (Book) to represent both a single book, and the whole store. Unpicking that is a fairly complex set of changes and decisions, though, so I'll just say that a class should represent a single kind of thing, and an object of the class represent an example of that kind. So normally Book and Bookstore are different kinds of thing. The vector in Book is an instance variable, meaning that every Book has its own vector of Books. That doesn't really make sense.
books refers to a vector of Book class. You are comparing Book to an integer, which is undefined behavior. You need to dereference the Book object before you can access its data members.
First, don't access vectors using subscript [] notation. It is inefficient and makes life difficult. Use an iterator (something like, not sure on how you would want to implement):
for (std::vector::iterator it = books.begin(); it != books.end(); ++it)
{
}
That isn't your problem, however. You use the -> operator to dereference objects to get to their members. You made your members private, however, so you either need a get function like
ISBNf() { return ISBNfirst; }
Or make your members public, but that is a bad idea (people can fool with your data). However, for simplicity, assume they are public, this is what you want:
for (std::vector::iterator it = books.begin(); it != books.end(); ++it)
{
if (*this == *it) cout << "test";
}
There is no good solution, here, because I have no idea what you are trying to achieve. I think you are trying to compare the number of digits on the integer, but this is not how to achieve that. If you are just trying to make sure you are assigning ISBNfirst properly, let me put your mind to rest: you are. However, you aren't accessing them correctly, which is where the -> operator comes in.
Next, this code is overkill:
else if(!isdigit(ISBNlast) && !isalpha(ISBNlast)
instead, use the isalphnum() function:
else if (!isalphnum(ISBNlast));
Posted; I will edit my post to point out all the flaws in your code.