#include "User.h"
#include <vector>
using namespace std;
User::User(){
username;
password;
}
User::User(const string& uname, const string& pass){
username = uname;
password = pass;
}
string User::get_username() const{
return username;
}
bool User::check(const string &uname, const string &pass) const{
if(username == uname && password == pass){
return true;
}
else{
return false;
}
}
In user.cpp, I am attempting to use the User::check function to check a username and password against a vector in board.cpp.
#include "BBoard.h"
#include "User.h"
#include <fstream>
#include <algorithm>
using namespace std;
User user_l;
BBoard::BBoard(){
title = "Default BBoard";
vector<User> user_list;
User current_user;
vector<Message> message_list;
}
BBoard::BBoard(const string &ttl){
title = ttl;
}
void BBoard::setup(const string &input_file){
ifstream fin;
string name, pass;
fin.open(input_file.c_str());
while(fin.good()){
fin >> name >> pass;
user_l = User(name, pass);
user_list.push_back(user_l);
}
}
void BBoard::login(){
string sn, pw;
cout << "Welcome to " << title;
bookmark:
cout << "\nEnter your username ('Q' or 'q' to quit): ";
getline(cin, sn);
if((sn == "Q" || sn == "q")){
cout << "Bye!";
exit(0);
}
cout << "Enter your password: ";
getline(cin, pw);
for(int i = 0; i < user_list.size(); i++){
if(user_list.at(i).check(sn, pw) == true){
cout << "Welcome back " << sn << "!" << endl;
User copy(sn, pw);
User current_user = copy;
}
else{
cout << "Invalid Username or Password!" << endl;
goto bookmark;
}
}
}
However, I am having great difficulty implementing the check function in login as my for loop in login doesn't seem to do anything and just simply runs along. How can I use implement check into my login function so that when the user enter a username and password in sn and pw, I can use check to reference it against the vector user_list to determine if it is a valid login or not?
Edit:
header for board
#ifndef BBOARD_H
#define BBOARD_H
#include <iostream>
#include <string>
#include <vector>
#include "User.h"
#include "Message.h"
using namespace std;
class BBoard{
private:
string title;
vector<User> user_list;
User current_user;
vector<Message> message_list;
public:
BBoard();
BBoard(const string &ttl);
void setup(const string &input_file);
void login();
};
#endif
and the header for user
#ifndef USER_H
#define USER_H
#include <string>
using namespace std;
class User{
private:
string username;
string password;
public:
User();
User(const string& uname, const string& pass);
string get_username() const;
bool check(const string &uname, const string &pass) const;
//void set_password(const string &newpass);
};
#endif
Edit:
new login
void BBoard::login(){
string sn, pw;
cout << "Welcome to " << title;
bookmark:
cout << "\nEnter your username ('Q' or 'q' to quit): ";
getline(cin, sn);
if((sn == "Q" || sn == "q")){
cout << "Bye!";
exit(0);
}
cout << "Enter your password: ";
getline(cin, pw);
for(int i = 0; i < user_list.size(); i++){
if(user_list.at(i).check(sn, pw) == true){
cout << "Welcome back " << sn << "!" << endl;
User copy(sn, pw);
User current_user = copy;
break;
}
else{
cout << "Invalid Username or Password!" << endl;
while(user_list.at(i).check(sn, pw) == false){
getline(cin, sn);
if((sn == "Q" || sn == "q")){
cout << "Bye!";
exit(0);
}
cout << "Enter your password: ";
getline(cin, pw);
}
}
}
}
While I didn't want to write your assignment for you, there are too many errors to comment on as there seems to be some misunderstanding of member initialization and variable scope. Below I've edited your code for you to compare what might be missing...I don't have a compiler handy right now so I can't 100% test this but this is your assignment so I recommend you try the code out yourself :)
BBoard.h
#ifndef BBOARD_H
#define BBOARD_H
#include <string>
#include <vector>
#include "User.h"
#include "Message.h"
class BBoard{
private:
std::string title;
std::vector<User> user_list;
User current_user;
std::vector<Message> message_list;
public:
BBoard();
BBoard(const std::string &ttl);
void setup(const std::string &input_file);
void login();
};
#endif
User.h
#ifndef USER_H
#define USER_H
#include <string>
class User{
private:
std::string username;
std::string password;
public:
User();
User(const std::string& uname, const std::string& pass);
std::string get_username() const;
bool check(const std::string &uname, const std::string &pass) const;
//void set_password(const string &newpass);
};
#endif
User.cpp
#include "User.h"
#include <vector>
User::User() : username(), password() { }
User::User(const std::string& uname, const std::string& pass)
: username(uname), password(pass)
{
}
std::string User::get_username() const {
return username;
}
bool User::check(const std::string &uname, const std::string &pass) const
{
return ((username == uname) && (password == pass));
}
BBoard.cpp
#include "BBoard.h"
#include "User.h"
#include <fstream>
#include <algorithm>
BBoard::BBoard()
: title("Default BBoard"),
user_list(),
current_user(),
message_list()
{
}
BBoard::BBoard(const std::string &ttl)
: title(ttl),
user_list(),
current_user(),
message_list()
{
}
void BBoard::setup(const std::string &input_file)
{
std::string name, pass;
std::ifstream fin(input_file.c_str());
while(fin.good()) {
fin >> name >> pass;
user_list.push_back(User(name, pass));
}
fin.close();
}
void BBoard::login()
{
std::string sn, pw;
bool found = false;
std::cout << "Welcome to " << title << std::endl;
while (!found) {
found = false;
std::cout << "\nEnter your username ('Q' or 'q' to quit): ";
std::cin >> sn; std::cin.clear();
if((sn == "Q" || sn == "q")){
std::cout << "Bye!";
break;
}
std::cout << "Enter your password: ";
std::cin >> pw; cin.clear();
std::vector<User>::iterator itr = user_list.begin();
while (itr != user_list.end() {
if (itr->check(sn, pw)) {
std::cout << "Welcome back " << sn << "!" << std::endl;
// this code does nothing except create a local scope (in this 'if' block only) User object
User copy(sn, pw);
User current_user = copy;
// copy and current_user are destroyed after the break statement
found = true;
break;
}
}
if (!found) { std::cout << "Invalid Username or Password!" << std::endl; }
}
}
I hope that can help
One solution is to add an operator == for your User class and call std::find().
#include <algorithm>
class User
{
std::string uname;
std::string password;
public:
bool operator ==(const User& u) const
{ return uname == u.uname && password == u.password; }
//...
};
void BBoard::login()
{
User testUser;
// assign testUser the credentials they are logging in with
//...
// check if user is in our vector
std::vector<User>::iterator itFound = std::find(user_list.begin(),
user_list.end(), testUser);
if ( itFound != user_list.end())
{
// user exists
}
}
Using find_if() if not allowed to change User class:
#include <algorithm>
struct FindUser
{
User u;
FindUser(const User& theUser) : u(theUser) {}
bool operator()( const User& theUser) const
{ return u.check(theUser); }
};
void BBoard::login()
{
User testUser;
// assign testUser the credentials they are logging in with
//...
// check if user is in our vector
std::vector<User>::iterator itFound = std::find_if(user_list.begin(),
user_list.end(),
FindUser(testUser));
if ( itFound != user_list.end())
{
// user exists
}
}
I believe your problem comes from the fact that you are declaring and initializing the same variables at different scopes so while you think you're modifying a member variable, you're in fact modifying a local variable which gets deleted as soon as it gets out of scope.
For example you have a member variable called current_user in the BBoard class. In the constructor you call User current_user; which in no way affects the member variable, but instead creates a new local variable with the same name. You then do the same thing in several places.
Once a member variable has been declared in the header, you use it by calling its name and without specifying its type again. Therefore to assign to current_user member variable in a function you shouldn't write:
User current_user = copy; // Declares new local variable
but instead write:
current_user = copy; // Uses a member variable declared in the header
As you make this mistake in several places, I assume this is causing your problem, as you are probably using a local variable while you mean to use a member one. Please check your code and make sure you're not redeclaring member variables at local scope.
To avoid confusion it is a good practice at add a prefix or a postfix to the name of your member variables so they are easily spotted. E.g. you could call your current_user member variable: m_current_user or current_user_.
Related
I have a banking project and I am trying to set up the bank name, address, and working hours. My getlines are showing an error as well as my get functions.
Input exact error messages here please.
'getline': no matching overloaded function found
no suitable user-defined conversion from "Bank" to "std::string" exists
Here's the class for bank:
#include <iostream>
#include <string>
#include <vector>
#include <ctime>
#include <cctype>
#include <cstdlib>
using namespace std;
class Bank {
public:
void setBankName(string bn) { bn = bankname; }
string getBankName() { return bankname; }
void setBankAdd(string ba) { ba = bankadd; }
string getBankAdd() { return bankadd; }
void setWorkingHours(string bwh) { bwh = bankworkinghours; };
string getWorkingHours() { return bankworkinghours; }
private:
string bankname, bankadd, bankworkinghours;
};
//and then this is in my main function
int main() {
Bank bankname, bankadd, bankworkinghours;
char userChoice; // numbers 1-9
int number=0;
system ("color 5f");
cout << "Name of bank: ";
getline(cin, bankname); **//all the get lines also show error**
cout << endl;
cout << "Bank address: ";
getline(cin, bankadd);
cout << endl;
cout << "Bank working hours: ";
getline(cin, bankworkinghours);
cout << endl;
bankname.setBankName(bankname); //the things in the parentheses show error
bankadd.setBankAdd(bankadd);
bankworkinghours.setWorkingHours(bankworkinghours);
The error is self explanatory. 2nd parameter of getline function is std:string so define bankname as std:string and then set the name of bank object by setBankName.
1- You did not created bank Object in the main to set class attributes.
You need an Object with reference to that object you will set the parameters of the class bank.
2- bankname, bankadd, bankworkinghours are string and you made them Bank
Here is updated code and working fine in VS 2019 without any error. Just a few changes in the first 2 and last three lines of main
#include <iostream>
#include <string>
#include <vector>
#include <ctime>
#include <cctype>
#include <cstdlib>
using namespace std;
class Bank {
public:
void setBankName(string bn) { bn = bankname; }
string getBankName() { return bankname; }
void setBankAdd(string ba) { ba = bankadd; }
string getBankAdd() { return bankadd; }
void setWorkingHours(string bwh) { bwh = bankworkinghours; };
string getWorkingHours() { return bankworkinghours; }
private:
string bankname, bankadd, bankworkinghours;
};
//and then this is in my main function
int main() {
Bank bankObj;
string bankname, bankadd, bankworkinghours;
char userChoice; // numbers 1-9
int number = 0;
system("color 5f");
cout << "Name of bank: ";
getline(cin, bankname);
cout << endl;
cout << "Bank address: ";
getline(cin, bankadd);
cout << endl;
cout << "Bank working hours: ";
getline(cin, bankworkinghours);
cout << endl;
bankObj.setBankName(bankname);
bankObj.setBankAdd(bankadd);
bankObj.setWorkingHours(bankworkinghours);
}
void setBankName(string bn) { bn = bankname; } is the wrong way around. try bankname = bn.
So I am trying to use a loop in the email setter where if it isn't valid it should repeat the user input email prompt. The thing is, if I type in a valid email at first it will break the loop which is what I want but if I type in an invalid email first it will repeat the loop twice and then if I type in a valid email after that it will still repeat the loop and I'm just stuck in an infinite loop. I know I'm probably doing something stupid but I can't seem to get it working.
User.cpp
#include "pch.h"
#include "User.h"
//Email regex
std::string userEmailRegex = ".+#.+";
//Validates data against a user-defined string
bool validate(std::string regexStr, std::string data)
{
return std::regex_match(data, std::regex(regexStr));
}
User::User()
{
}
User::User(std::string email, std::string password, std::string username)
{
setEmail(email);
setPassword(password);
setUsername(username);
}
User::~User()
{
}
void User::setEmail(std::string email)
{
bool bValid = validate(userEmailRegex, email);
for (;;)
{
if (bValid)
{
this->email = email;
break;
}
else
{
std::cout << "Please enter a valid email adress!\n";
std::cout << "Email: ";
std::cin.clear();
std::cin.ignore(512, '\n');
}
}
}
Main.cpp
#include "pch.h"
#include "User.h"
#include "DkDateTime.h"
User u;
int main()
{
std::cout << "Welcome to MySocialNetwork!\n";
std::cout << "Please Login below:\n";
std::cout << std::endl;
std::vector<User> v;
std::string email;
std::cout << "Email: ";
std::cin >> email;
u.setEmail(email);
std::cout << u.getEmail() << std::endl;
std::cout << std::endl;
}
It looks like you've misplaced your validation code, and inside your setEmail code you never stored the email that the user input
void User::setEmail(std::string email)
{
for (;;)
{
bool bValid = validate(userEmailRegex, email);
if (bValid)
{
this->email = email;
break;
}
else
{
std::cout << "Please enter a valid email adress!\n";
std::cout << "Email: ";
std::cin.clear();
std::cin.ignore(512, '\n');
std::cin >> email;
}
}
}
so if you move bool bValid = validate(userEmailRegex, email); into the loop instead, you should get the expected result.
OBS: not tested but should get you toward the correct validation
You receive an email address as a parameter to a setter method, fine. But then, if it is not valid, you loop asking a new string from stdin, inside the setter method which is at least a questionable design. It will prevent to use that class in a batch context or in a service getting its input from HTTP messages or anything else not tightly bound to a terminal.
For the sake of separation of concerns, the loop should be outside of the user class: it is a UI concern, not user management. IMHO you should make validate a User class static method and move the loop into the main function:
//Validates data against a user-defined string
static bool User::validate(std::string data)
{
//Email regex
static std::string userEmailRegex = ".+#.+";
return std::regex_match(data, std::regex(User::regexStr));
}
void User::setEmail(std::string email, bool validated = false)
{
if (! (validated || validate(userEmailRegex, email))) {
raise std::invalid_argument("Invalid email");
}
this->email = email;
}
int main()
{
...
for (;;) {
std::cout << "Email: ";
std::cin >> email;
if (User::validate(email)) {
u.setEmail(email);
break;
}
else {
std::cout << "Please enter a valid email adress!\n";
}
}
std::cout << u.getEmail() << std::endl;
std::cout << std::endl;
}
I'm writing a library application. Part of the application is allowing users to login. I'm using a vector of structs to store the usernames/passwords. When I try to access a member variable of the struct, I get an out of range error. The vector is full (I checked with both the vector.size and vector.empty methods), and I believe I am assigning values to the member variables correctly (although clearly I'm not).
Here is main.cpp:
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include "userService.h"
using namespace std;
void countRecords(string& pathName, ifstream& inFile);
void loadCredentials(string pathName, ifstream& inFile, string& username, string& password, userService newUser);
void login(string username, string password, userService newUser, bool& loggedIn);
int numRecords;
int main()
{
string username, password;
string pathName = "/home/seth/Desktop/credentials";
ifstream inFile;
userService newUser;
char menuSelection;
bool loggedIn = false;
countRecords(pathName, inFile);
cout << "Welcome to Library Information System." << endl << endl;
do{
cout << "choose a) to login or b) to register as a new user." << endl << endl;
cin >> menuSelection;
switch (menuSelection)
{
case 'a':
{
cout << "Username: ";
cin >> username;
cout << endl;
cout << "Password: ";
cin >> password;
cout << endl;
loadCredentials(pathName, inFile, username, password, newUser);
login(username, password, newUser, loggedIn);
if (loggedIn == true)
{
cout << "You logged in! " << endl; //placeholder, will be more menu options here
}
else
{
cout << "Invalid credentials! Please check your username and password and try again!" << endl;
}
break;
}
}
} while (loggedIn == false);
return 0;
}
void countRecords(string& pathName, ifstream& inFile)
{
string temp; //string to count records using getline
inFile.open(pathName);
while (inFile)
{
getline(inFile, temp, '\n');
if (inFile.eof())
{
break;
}
++numRecords;
}
cout << "numRecords = " << numRecords << endl;
inFile.close();
inFile.clear(std::ios_base::goodbit);
}
void loadCredentials(string pathName, ifstream& inFile, string& username, string& password, userService newUser)
{
string tempUsername, tempPassword;
inFile.open(pathName);
if (!inFile)
{
cout << "Error opening file" << endl;
}
for (int i = 0; i < numRecords; i++)
{
getline(inFile, tempUsername, ',');
getline(inFile, tempPassword, '\n');
newUser.loadCredentials(tempUsername, tempPassword);
}
}
void login(string username, string password, userService newUser, bool& loggedIn)
{
newUser.resetVectorCounter();
for (size_t i = 0; i < numRecords; i++)
{
cout << "i = " << i << endl;
cout << newUser.getUsername() << endl;
cout << newUser.getPassword() << endl;
newUser.incrementVector();
}
}
userService.h:
#include <string>
#include <fstream>
#include <vector>
using namespace std;
struct credentials
{
string username = "";
string password = "";
};
class userService
{
private:
vector<credentials> credentialsList;
int vectorCounter = 0;
string username_, password_;
public:
void loadCredentials(string username_, string password_);
bool check();
int sizeOfVec();
string getUsername();
string getPassword();
void incrementVector();
void resetVectorCounter();
};
Implementation of userService:
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include "userService.h"
using namespace std;
credentials users;
void userService::loadCredentials(string username_, string password_)
{
users.username = username_;
users.password = password_;
credentialsList.push_back(users);
}
bool userService::check()
{
return credentialsList.empty();
}
int userService::sizeOfVec()
{
return credentialsList.size();
}
string userService::getUsername()
{
return credentialsList.at(vectorCounter).username;
}
string userService::getPassword()
{
return credentialsList.at(vectorCounter).password;
}
void userService::incrementVector()
{
vectorCounter++;
}
void userService::resetVectorCounter()
{
vectorCounter = 0;
}
The exact error that is being thrown is:
'std::out_of_range'
what(): vector::_M_range_check: __n (which is 0) >= this->size (which is 0)
This happens immediately after calling getUserName. I believe this means the member variables are empty, but if so, I do not know how to assign them values properly. Any help would be appreciated.
I've tried using a debugger, and here is where the debugger shows this problem is:
protected:
/// Safety check used only from at().
void
_M_range_check(size_type __n) const
{
if (__n >= this->size())
__throw_out_of_range_fmt(__N("vector::_M_range_check: __n "
"(which is %zu) >= this->size() "
"(which is %zu)"),
__n, this->size());
}
Your code does indeed accesses a std::vector using an out of bounds index.
Here's the stack trace from gdb on my machine:
#0 0x00007ffff74aa428 in __GI_raise (sig=sig#entry=6)
at ../sysdeps/unix/sysv/linux/raise.c:54
#1 0x00007ffff74ac02a in __GI_abort () at abort.c:89
#2 0x00007ffff7ae484d in __gnu_cxx::__verbose_terminate_handler() ()
from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#3 0x00007ffff7ae26b6 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#4 0x00007ffff7ae2701 in std::terminate() ()
from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#5 0x00007ffff7ae2919 in __cxa_throw ()
from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#6 0x00007ffff7b0b3f7 in std::__throw_out_of_range_fmt(char const*, ...) ()
from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#7 0x00000000004029b6 in std::vector<credentials, std::allocator<credentials> >::_M_range_check (this=0x7fffffffe320, __n=0)
at /usr/include/c++/5/bits/stl_vector.h:803
#8 0x00000000004024cf in std::vector<credentials, std::allocator<credentials> >::at (this=0x7fffffffe320, __n=0) at /usr/include/c++/5/bits/stl_vector.h:824
#9 0x000000000040179d in userService::getUsername[abi:cxx11]() (
this=0x7fffffffe320) at socc.cc:61
#10 0x0000000000402059 in login (username="a", password="aa", newUser=...,
loggedIn=#0x7fffffffe19f: false) at socc.cc:185
#11 0x0000000000401aa4 in main () at socc.cc:120
My "credentials" file has the following lines:
a,aa
b,bb
c,cc
Hence, when I use "a" for username and "aa" as password, the login should have succeeded.
However, you have:
string userService::getUsername()
{
return credentialsList.at(vectorCounter).username;
}
when that function is called, credentialsList is empty and vectorCounter is 0. That is not OK.
That explains why you get the error. However, the fix is not simple.
I think there is lack of clarity on your part as far as how the data from the "credentials" file needs to be stored and how they can be used to authenticate users.
Here are some points to ponder.
userService can provide the ability to authenticate users. However, it is not a user. Hence, it makes no sense at all why you have username_ and password_ as member variables of the class.
The list of credentials from the "credentials" file is global data of your program. It makes no sense to store them in a member variable of userService unless your program can guarantee that there is only instance of userService.
Having vectorCounter as a member variable of userService makes no sense at all either. When you need to iterate over the elements of the vector, there are better alternatives. Not only that, the logic for iteration should be local to the function, and any local variables thereof should be function local variables.
Many of the member functions of userService are not appropriate for the responsibility of the class. The only member functions that make sense to me are:
void loadCredentials(string filename);
bool authenticateUser(credentials const& c);
Here's an updated program that works for me (except that you don't have any code for user choice 'b').
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
struct credentials
{
string username;
string password;
};
class userService
{
private:
vector<credentials> credentialsList;
public:
void loadCredentials(string filename);
bool authenticateUser(credentials const& c);
};
void userService::loadCredentials(string filename)
{
string tempUsername, tempPassword;
std::ifstream inFile(filename);
if (!inFile)
{
cout << "Error opening file" << endl;
}
while (inFile )
{
if ( !getline(inFile, tempUsername, ',') )
{
return;
}
if ( !getline(inFile, tempPassword, '\n') )
{
return;
}
credentialsList.push_back(credentials{tempUsername, tempPassword});
}
}
bool userService::authenticateUser(credentials const& c)
{
for ( auto const& item : credentialsList )
{
if ( item.username == c.username &&
item.password == c.password )
{
return true;
}
}
return false;
}
int main()
{
string username, password;
// string pathName = "/home/seth/Desktop/credentials";
string pathName = "credentials";
// The only instance of userService used in the program.
userService service;
char menuSelection;
bool loggedIn = false;
// Load the credentials file once and then use for all subsequent checks.
service.loadCredentials(pathName);
cout << "Welcome to Library Information System." << endl << endl;
do {
cout << "choose a) to login or b) to register as a new user." << endl << endl;
cin >> menuSelection;
switch (menuSelection)
{
case 'a':
{
cout << "Username: ";
cin >> username;
cout << endl;
cout << "Password: ";
cin >> password;
credentials c = {username, password};
// The only instance of userService has all the credentials.
// It can authenticate the user credentials.
loggedIn = service.authenticateUser(c);
if (loggedIn)
{
cout << "You logged in! " << endl; //placeholder, will be more menu options here
}
else
{
cout << "Invalid credentials! Please check your username and password and try again!" << endl;
}
}
break;
// Missing code for case 'b'
// case 'b':
}
} while (loggedIn == false);
return 0;
}
Maybe it's because I've been staring at this for 5 hours straight and I'm just reading over the obvious solution, but Xcode states that my vector of objects (that is declared in a header file) is undeclared in one .cpp file; however, my other .cpp file can access the vector, so I'm not sure what the problem is. Maybe my header files are out of place, or I'm unintentionally "circular referencing"?? Suggestions please?
publications.h
#ifndef PUBLICATIONS_H
#define PUBLICATIONS_H
#include "std_lib_facilities.h"
class Publication {
private:
string
publication_title,
publication_author,
publication_year,
publication_genre,
publication_media,
publication_target_age,
publication_ISBN;
bool currently_checked_out;
public:
Publication(string title, string author, string year, string genre, string media, string target_age, string ISBN, bool checked_out) {
publication_title = title;
publication_author = author;
publication_year = year;
publication_genre = genre;
publication_media = media;
publication_target_age = target_age;
publication_ISBN = ISBN;
currently_checked_out = checked_out;
}
Publication(){};
};
#endif /* PUBLICATIONS_H */
library.h
#ifndef LIBRARY_H
#define LIBRARY_H
#include "std_lib_facilities.h"
class Publication;
class Library {
private:
vector<Publication> lb;
public:
Library(){};
void documentation();
void list_all_publications();
void new_publication(string title, string author, string year, string genre, string media, string target_age, string ISBN, bool currently_checked_out);
};
#endif /* LIBRARY_H */
patron.h
#ifndef PATRON_H
#define PATRON_H
#include "std_lib_facilities.h"
class Publication;
class Patron {
private:
string
customer_name,
customer_telephone;
public:
void check_out_publication(string publication_requested);
void return_publication(string check_in_publication_name);
void check_out();
bool is_checked_out();
Patron(){};
};
#endif /* PATRON_H */
library.cpp (works perfectly fine, can access vector in library.h)
#include "library.h"
#include "patron.h"
#include "publications.h"
#include "std_lib_facilities.h"
Patron p;
void Library::documentation() {
cout << "\n-----Create a new publication----\n";
cout << "You will enter all the necessary info for a new publication (title, author, year, genre, media, target age, and ISBN).\n";
cout << "\n----List all Publications-----\n";
cout << "List all publications that have been entered (in this current session).\n";
cout << "\n---Check out Publication----\n";
cout << "You will enter your name and telephone number and the publication will be checked out.\n";
cout << "\n-----Return Publication------\n";
cout << "A previously checked out publication will be marked as returned.\n";
}
void Library::new_publication(string title, string author, string year, string genre, string media, string target_age, string ISBN, bool checked_out) {
lb.push_back(Publication(title, author, year, genre, media, target_age, ISBN, checked_out));
}
void Library::list_all_publications() {
for (int i = 0; i < lb.size(); i++) {
cout << "Title: " << "\tChecked Out: " << p.is_checked_out() << endl;
}
}
patron.cpp (problematic file, cannot access vector in library.h)
#include "publications.h"
#include "library.h"
#include "patron.h"
#include "std_lib_facilities.h"
void Patron::check_out_publication(string publication_requested) {
// check to make sure publication isn't already checked out.
for (int i = 0; i < lb.size(); i++) {
if ((publication_requested == lb[i].publication_title) && lb[i].currently_checked_out) {
cout << "Sorry, this publication is currently checked out." << endl;
} else if ((publication_requested == lb[i].publication_title) && !(lb[i].currently_checked_out)) {
cout << "Enter your name: ";
getline(cin, customer_name);
cout << "Enter your telephone number (no dashes/no spaces): ";
cin >> customer_telephone;
} else {
continue;
}
}
}
void Patron::return_publication(string check_in) {
for (int i = 0; i < lb.size(); i++) {
if ((check_in == lb[i].publication_title) && lb[i].currently_checked_out) {
// marked as no longer checked out.
lb[i].currently_checked_out = false;
}
}
}
bool Patron::is_checked_out() {
return currently_checked_out;
}
void Patron::check_out() {
currently_checked_out = true;
}
Error in patron.cpp
USE OF UNDECLARED IDENTIFIER "lb"
lb is a private member of the Library class. You can access it in your library.cpp file because you are using it within a Library member function. Whereas in the Patron class you're directly accessing it. But the compiler sees it as just another variable, which you haven't declared. Likely you need to add an accessor to Library.
User.h
#pragma once
#include <iostream>
#include <string>
#include <fstream>
#include <list>
class User
{
private:
char line1[50];
char line2[50];
char line3[50];
char line4[50];
public:
void getUser(std::string);
};
User.cpp
#include "User.h"
void getUser(std::string username)
{
std::ifstream fin(username + ".txt");
fin.getline(line1, 50);
fin.getline(line2, 50);
fin.getline(line3, 50);
fin.getline(line4, 50);
fin.close();
std::list<std::string> UserInfo;
UserInfo.push_back(line1);
UserInfo.push_back(line2);
UserInfo.push_back(line3);
UserInfo.push_back(line4);
return UserInfo;
}
main.cpp
#include "User.h"
std::string username;
User display;
std::cout << std::endl << "Please enter your username: ";
std::getline (std::cin, username);
display.getUser(username);
I want to access the list UserInfo in main - I'm assuming it has to be returned, however, I don't know what the return type would be? (void is just temporary until I know the return type).
The other problem I have is when accessing the char variables in User.cpp, line1, line2 etc, I am given the error:
Identifier "line1" is undefined.
Same as your list :
std::list<std::string> getUser(std::string username)
{
return UserInfo ;
}
Or pass it as a reference :
void getUser(std::string username, std::list<std::string>& UserInfo)
{
}
Char arrays line1, etc are private members can be accessed inside the member functions of class or through friend functions only.
Defined your getUser outside class
void User::getUser(std::string username)
{
}
Lets put everything together into one file so that we can make a stand-alone compilable version of it.
#include <string>
#include <list>
#include <iostream>
// make an alias for this type of list and call it 'UserInfo'.
typedef std::list<std::string> UserInfo;
class User
{
// private is the default for class, it's the only way
// it differs from using 'struct'.
char m_line1[50];
char m_line2[50];
char m_line3[50];
char m_line4[50];
public:
UserInfo getUser(const std::string&);
};
UserInfo User::getUser(const std::string& username)
{
std::ifstream fin(username + ".txt");
fin.getline(m_line1, sizeof(m_line1));
fin.getline(m_line2, sizeof(m_line1));
fin.getline(m_line3, sizeof(m_line1));
fin.getline(m_line4, sizeof(m_line1));
fin.close();
UserInfo info;
info.push_back(m_line1);
info.push_back(m_line2);
info.push_back(m_line3);
info.push_back(m_line4);
return info;
}
int main()
{
std::string username;
User display;
std::cout << std::endl << "Please enter your username: ";
std::getline(std::cin, username);
UserInfo info = display.getUser(username);
for (auto it = info.begin(); it != info.end(); ++it) {
std::cout << *it << "\n";
}
return 0;
}
Some remarks on your code:
Be consistent with your use of case. You're using what's called "UpperCamelCase" to denote types (User), use "lowerCamelCase" for variables and stick with it - otherwise you're going to run into collisions between variable names and types.
Secondly, you've chosen a std::list where a std::vector seems like it would be much better.
Next, you decouple the way you return your data and the way you store your data. Why not store the lines as std::strings?
Your "User" object is kind of vague and nebulous. It has some string fields, which you don't initialize when the object is created, and it has a function which goes and fetches data about a particular user, stores it in the object, and returns in a different format.
This is how I would implement the class:
#include <string>
#include <vector>
#include <iostream>
typedef std::vector<std::string> UserInfo;
class User
{
std::string m_username;
UserInfo m_info;
public:
User(const std::string& name);
enum { NumInfoLines = 4 }; // how many lines of info we use.
// Accessor function to retrieve the userinfo
// Instead of passing a copy, provide read-only access
// to our internal copy - read-only so you have to go thru
// the class to modify it.
// Mark the function call as 'const' because it has no
// side effects. This may allow the compiler to do some
// optimizations for us.
const UserInfo& getInfo() const { return m_info; }
};
User::User(const std::string& username)
: m_username(username), m_info()
{
std::ifstream fin(m_username + ".txt");
std::string inputLine;
m_info.reserve(NumInfoLines);
for (size_t i = 0; i < NumInfoLines; ++i) {
fin.getline(inputLine);
m_info.push_back(inputLine);
}
}
int main()
{
std::string username;
std::cout << std::endl << "Please enter your username: ";
std::getline(std::cin, username);
User user(username);
const UserInfo& info = user.getInfo();
for (auto line : info) {
std::cout << line << "\n";
}
/* or you could use
const size_t numInfoLines = info.size();
for (size_t i = 0; i < numInfoLines; ++i) {
std::cout << i << ": " << info[i] << "\n";
}
*/
return 0;
}