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;
}
Related
I am a student currently learning C++ and I need some help. I am currently working on a textbook exercise from the book Murach's C++ Programming. I am working on Exercise 7-2 (second exercise in chapter 7). The instructions for the program are here: Exercise 7-2 instructions I've managed to make sense of most of it, but I am currently stuck on step 9. I know how to call functions, but when I run the program, it only allows me to enter my full name. After I do that, the program ends without letting me enter my password or email. And yes I have added a return value to my variables as needed. How can I make the program let me enter my full name, password and email like it's supposed to? Nothing that I've tried seems to work. I've tried returning a value of 0, I've tried making a local variable and then adding the return value to said variable, but none of that worked. Please help me understand what I'm supposed to do as I'm still new to C++ and have a lot to learn. By the way, I'm using Microsoft Visual Studios as my IDE.
Here's the code that I have so far for my main.cpp file:
#include <iostream>
#include <string>
#include "validation.h"
using namespace std;
int main()
{
cout << "Create Account\n\n";
// get full name and parse first name
string full_name;
string first_name;
bool valid_name = false;
while (!valid_name) {
cout << "Enter full name: ";
getline(cin, full_name);
// strip whitespace from front
int i = full_name.find_first_not_of(" \n\t");
if (i > -1) {
full_name = full_name.substr(i);
}
// get first name
int space_index = full_name.find(' ');
if (space_index == -1) {
cout << "You must enter your full name. Please try again.\n";
}
else {
first_name = full_name.substr(0, space_index);
valid_name = true;
}
}
cout << endl;
bool validation::is_valid_password(string password);
bool validation::is_valid_email(string email);
// make sure first name uses initial cap
char letter = first_name[0];
first_name[0] = toupper(letter);
for (int i = 1; i < first_name.length(); ++i) {
letter = first_name[i];
first_name[i] = tolower(letter);
}
// display welcome message
cout << "Hi " << first_name << ",\n"
<< "Thanks for creating an account!\n\n";
}
And the code I have so far with the validation.cpp implementation file:
#include "validation.h"
#include <string>
#include <iostream>
using namespace std;
using namespace validation;
bool validation::is_valid_password(string password) {
bool valid_password = false;
while (!valid_password) {
valid_password = true;
cout << "Enter password: ";
getline(cin, password);
if (password.length() < 8) {
cout << "Password must be at least 8 characters.\n";
valid_password = false;
}
int index = password.find_first_of("0123456789");
if (index == -1) {
cout << "Password must include a number.\n";
valid_password = false;
}
bool special_character = false;
for (char c : password) {
if (ispunct(c)) {
special_character = true;
break;
}
}
if (!special_character) {
cout << "Password must include a special character.\n";
valid_password = false;
}
if (!valid_password) {
cout << "Please try again.\n";
}
else {
password = password.substr(0, index);
valid_password = true;
}
}
cout << endl;
return false;
}
bool validation::is_valid_email(string email) {
bool valid_email = false;
while (!valid_email) {
valid_email = true;
cout << "Enter email: ";
getline(cin, email);
int at_index = email.find('#');
if (at_index == -1) {
cout << "The email must include an at character (#).\n";
valid_email = false;
}
int dot_index = email.rfind('.');
if (dot_index == -1) {
cout << "The email must include a dot operator (.).\n";
valid_email = false;
}
bool valid_chars = true;
for (char c : email) {
if (c != '#' && c != '.' && c != '_' && c != '-') {
if (!isalnum(c)) {
valid_chars = false;
break;
}
}
}
if (at_index == 0) {
cout << "The local part of the email must include at least one character.\n";
valid_email = false;
}
if (dot_index - at_index == 1) {
cout << "The server name of the email must include at least one character.\n";
valid_email = false;
}
if (email.length() - dot_index - 1 != 3 && email.length() - dot_index - 1 != 2) {
cout << "The domain name of the email must have two or three characters.\n";
valid_email = false;
}
if (!valid_email) {
cout << "Please try again.\n";
}
else {
email = email.substr(0, at_index);
email = email.substr(0, dot_index);
valid_email = true;
}
}
cout << endl;
return false;
}
And the code I have for the validation header file:
#ifndef T_FRYE_VALIDATION_H
#define T_FRYE_VALIDATION_H
#endif // !T_FRYE_VALIDATION_H
#include <string>
using namespace std;
namespace validation {
bool is_valid_password(string password);
bool is_valid_email(string email);
}
I know that this is a lot to read, and I'm really sorry about that, but I'm at a loss as to what to do next. If anyone can help me, I'd really appreciate it.
The calls to your validation functions are malformed. You attempt to call the code
validation::isvalid_password(); from main but what you provide instead is:
bool validation::is_valid_password(string password);
bool validation::is_valid_email(string email);
which are declarations. You need to actually call the code you want.
string password;
string email;
validation::isvalid_password(password);
validation::is_valid_email(email);
What do you think these two lines do inside the main() function?
int main()
{
// ...
bool validation::is_valid_password(string password);
bool validation::is_valid_email(string email);
// ...
}
That is not a function call, that is just a declaration of the function. You should have something like:
int main()
{
// ...
std::string password;
while (!validation::is_valid_password(password));
std::string email;
while (!validation::is_valid_email(email));
// ...
}
There are many other problems in your code anyway... For example, if you are reading something inside the function is_valid_xxx (which is a bad design by itself because is_-type of functions shouldn't do anything except checking the values), you should pass the string by reference:
bool validation::is_valid_password(string &password);
Even if you don't plan to get the new value, passing something by value is a bad idea in this type of functions. Pass the value by reference to const:
bool validation::is_valid_password(const string &password);
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;
}
class Message {
public:
void changeSubject(string);
string getSubject();
private:
string subject;
};
void Message::changeSubject (string subjecto) //change subject{
subject = subjecto;
}
string Message::getSubject () //return subject {
return subject;
}
int main ()
{
Message person;
string aboutwhat;
cout << "Enter subject" << endl;
getline(cin, aboutwhat);
person.changeSubject(aboutwhat);
cout << person.getSubject();
return 0;
}
Above isn't the full code. The problem right now is that it prints "Enter Subject" and ends the program. Why am I not prompted to cin?
Your code as posted has several issues and doesn't compile. The following works for me
// Include al necessary headers:
#include <iostream>
#include <string>
// Either qualify the namespace of `std::string`, `std::cin`, etc
// or place a using statement like follows
using namespace std;
class Message {
public:
void changeSubject(string);
string getSubject();
private:
string subject;
};
void Message::changeSubject (string subjecto) //change subject
{ // <<< You have hidden the opening brace after the comment above
subject = subjecto;
}
string Message::getSubject () //return subject
{ // <<< You have hidden the opening brace after the comment above
return subject;
}
int main ()
{
Message person;
string aboutwhat;
cout << "Enter subject" << endl;
getline(cin, aboutwhat);
person.changeSubject(aboutwhat);
cout << person.getSubject();
return 0;
}
See the working sample here please.
Since you have stated in your question, "This isn't the full code", I'd suspect you have some error in the other parts that weren't shown.
"Why am I not prompted to cin?"
One likely possibility is you have had other inputs on cin before, that were invalid and cin got into fail() state.
To prevent this, you can put a cin.clear(); statement before the getline() call.
If you take inputs like e.g. numbers, you should check for validity like this
int x;
do {
cout << "Enter a number please: "
if(cin >> x) {
break;
}
cout << "Not a valid number, try again." << endl;
cin.clear();
} while(true);
Since your code above looks correct.
I would suggest you first get the prompting working first.
Then add back more code later.
I just tested the following in my own environment
#include <iostream>
#include <string>
main ()
{
std::string aboutwhat;
std::cout << "Enter subject" << std::endl;
std::getline (std::cin,aboutwhat);
std::cout << "Subject: " << aboutwhat << std::endl;
return 0;
}
Okay, so this is effectively the first C++ I have ever written. Consequently, my attempts to research this Segmentation Fault error have failed to yield a useful response that I can understand. Most suggestions say that I'm exceeding the heap memory, but I don't see how I could be in this code. Maybe I'm trying to reference something that I can't reference?
Can someone please take a look at this code and possibly tell me what is causing this error? The code compiles fine, it just throws this error when it runs. I have tried commenting out all the code involving vectors, and that didn't solve the problem. I'm guessing it's something stupid that I'm missing or just a concept about C++ that I don't understand. Either way, some insight would be much appreciated! Thanks in advance.
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
const int DEFAULT_SIZE = 15;
//---------------------------------User----------------------------------------------------------------------------------
//User Interface Definition
class User
{
public:
User(string nameValue);
string getName();
string getWall();
string getHome();
private:
string name;
};
//User Implementation Definition
User::User(string nameValue) : name(nameValue)
{
}
string User::getName()
{
return name;
}
//---------------------------------Group----------------------------------------------------------------------------------
//Group Interface Definition
class Group
{
public:
Group(string nameValue);
string getName();
void addMember(User newMember);
private:
string name;
vector<User> members;
};
//Group Implementation
Group::Group(string nameValue) : name(nameValue)
{
}
string Group::getName()
{
return name;
}
void Group::addMember(User newMember)
{
members.push_back(newMember);
}
//---------------------------------MessageBuffer----------------------------------------------------------------------------------
//MessgeBuffer Interface Declaration
class MessageBuffer
{
public:
MessageBuffer();
void insert(string user, string recipient, string message);
string readByGroup(string groupName);
string readByUser(string userName);
string readPublic();
private:
string buffer;
};
//MessageBuffer Implementation
MessageBuffer::MessageBuffer() : buffer("")
{
}
void MessageBuffer::insert(string user, string recipient, string message)
{
buffer = "|<" + user + "::" + recipient + ">|" + message + buffer;
}
string MessageBuffer::readByGroup(string groupName)
{
return "Something";
}
string MessageBuffer::readByUser(string userName)
{
return "Something";
}
string MessageBuffer::readPublic()
{
return "Something";
}
//---------------------------------System-------------------------------------------------------------------------------
//System Interface Definition
class System
{
public:
System();
void start();
private:
bool running;
User currentUser;
MessageBuffer messageBuffer;
vector<User> users;
vector<Group> groups;
};
//System Implementation Definition
System::System() : running(false), currentUser(0)
{
}
void System::start()
{
running = true;
string userSelection;
cout << "===========================================================" << endl;
cout << "|\t Welcome to the Auburn Messaging System! \t |" << endl;
cout << "===========================================================" << endl;
while (running) {
cout << "1) Create a new user\n";
cout << "2) Broadcast a message\n";
cout << "3) Multicast a message\n";
cout << "4) Unicast a message\n";
cout << "5) Display Wall page\n";
cout << "6) Display Home page\n";
cout << "7) Create a new group\n";
cout << "8) Join a group\n";
cout << "9) Switch to a different user\n";
cout << "10) Quit Auburn Messaging System\n";
cin >> userSelection;
if (userSelection == "1")
{
running = false;
}
}
}
//----------------------------------------------------------------------------------------------------------------------
int main() {
cout << "Part 1";
System system1;
cout << "Part 2";
system1.start();
cout << "Part 3";
return 0;
}
In the System constructor, currentUser(0) is attempting to initialise a the first parameter of the User constructor (a string) with a literal zero which will be interpreted as a null char pointer.
The std::string constructor (look for basic_string<char> in the debugger) which constructs a string from a char* will be called with a null pointer, which it will dereference and invoke undefined behaviour.
#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_.