Creating objects using data from text file.

Pages: 12
closed account (y3hk216C)
Hello, I need help with solving a problem of mine. I have a text file with information separated by tabs. For example, a text file contains:

1
2
3
Jason Matthews    1997    6782349567    user1997    pass1997
Kelsey James    1980    2484560234     user1980    pass1980   
John Doe    1990    4567890231    user1990    pass1990   


I have a user.cpp file that contains get and set functions for the name, birth year, phone number, username, and password. I then have a main.cpp where I basically allow the user to login and prompt them so they can choose to see either their name, birth year, phone number and their user name and password.

I have the code to properly allow them to login with the correct username and password combination, however, I am not sure how to approach allowing them to access their information. I want to utilize the get functions when I go to display their information, but I don't know how to go about setting the user object information from the info in the text file.

I am relatively new to C++ so I apologize if this seems a bit basic or easy to do, perhaps I have spent too long trying to solve this today and need to take a break. I appreciate the help!!!
Last edited on
I want to utilize the get functions when I go to display their information, but I don't know how to go about setting the user object information from the info in the text file.


This really depends on how your class is defined and how you're actually using the class. So in order to help you will probably need to post some code.

Also in future you may want to post the contents of your file inside code tags to preserve formatting.

1
2
3
4
5
6
7
8
9
10
11
container<User> users
repeat
	read_name(input, name)
	read_year(input, year)
	read_some_number(input, some_number)
	read_nick(input, nick)
	read_password(input, password)
	users.insert( create_user(name, year, some_number, nick, password) )

who_am_i = find_user( users, nick, password )
display_user(who_am_i)
¿what part do you need help with?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <iostream>
#include <string>
#include <fstream>

using namespace std;

struct UserData {
    UserData() :birthYear(-1), number(-1) {}

    string firstName;
    string lastName;
    int birthYear;
    int number;
    string username;
    string password;
};

UserData GetData(string username, const char* file)
{
    ifstream infile;
    UserData tmp;
    infile.open(file);
    if (infile.fail())
        return UserData();    // failed to open file return an 'invalid' user
    
    while (!infile.eof())
    {
        infile >> tmp.firstName
                >> tmp.lastName
                >> tmp.birthYear
                >> tmp.number
                >> tmp.username
                >> tmp.password;

        if (tmp.username == username)
            return tmp;     // user found
    }
 
    infile.close();
    return UserData();    // user not found return an 'invalid' user
}

int main()
{
    UserData user = GetData("user1", "database.txt");
    if (user.birthYear != -1)
    {
        cout << "user exists!" << endl;

        // Display user data
        cout << user.firstName << endl
               << user.lastName << endl
               << user.birthYear << endl
               << user.number << endl
               << user.username << endl
               << user.password << endl;
    }
    else
        cout << "mhmm, user does not exist :'(" << endl;

    system("PAUSE");
}
Last edited on
closed account (y3hk216C)
@jlb My user.cpp file looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
User::User(){}//Default constructor bc im not sure how to fill the values with param 
//If the data is in a text file
string getName() {
 return Name;
}
int User::getBirthYear() {
return birthYear;
}
int User::getPhoneNum() {
return phoneNum;
}
string User::getUserName() {
return userName;
}
string User::getPassword() {
return password;
}

void User::setName(string name) {
this->name = name;
}
void User::setBirthYear(int birthYear) {
this->birthYear = birthYear;
}
void User::setPhoneNum(int phoneNum) {
this->phoneNum = phoneNum;
}
void User::setUserName(string userName) {
this->userName = userName;
}
void User::setPassword(string password) {
this->password = password;
}

(I have a header file for the user class as well that is set up with all the variables and functions)

Then in my main class, I would want to use it like this(Omitting the login code for simplicity):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int main() 
{

 //First user logs in and is properly vetted to see if they are a user from the txt files.
User userObject;
int userInput;
cout << "Type 1 for name, type 2 for birth year, type 3 for phone number, type 4 for username, type 5 for password." << endl;
cin >> userInput;

if(userInput == 1) 
{
 cout<< "Your name is " << userObject.getName() << endl;
}
if(userInput == 2)
{
 cout << "You birth year is " << userObject.getBirthYear() << endl;
}
//etc etc
}

Last edited on
why using these set and get functions when your class doesn't need them, an expert would recommend to put the data in a struct for simple data access, check my previous reply it shows how to use ifstream to read data from a file and store it in an object "UserData" then you can process or display that data however you like. I assume that your class doesn't inherit from another class, so why using the this pointer, it just makes the code look uglier. plus in the constructor you must initialize the integer values otherwise you may deal with some weird random numbers. the getPassword and getUsername funcs both return integer values when they should return strings that is why I told you to use structs as my code shows in my previous reply.
I hope I answered your question.
Last edited on
closed account (y3hk216C)
@fewdiefie Yes I saw, I apologize, I haven't done anything with structs yet so I unfamiliar with them at the moment. Your code did help me conceptualize it better though!
Last edited on
@ckh85222 You don't have to apologize :D we all were beginners at a time, good luck.
an expert would recommend to put the data in a struct for simple data access,

Not necessarily, there is nothing wrong with using a class, and remember the only real difference between a struct and a class is the default access specifiers. Also by using public access you allow any function to modify the member variables, private access limits the access to class member functions, which usually leads to better data encapsulation.

check my previous reply it shows how to use ifstream to read data from a file and store it in an object "UserData" then you can process or display that data however you like.

Yea, a code dump without any real explanation, great.

I assume that your class doesn't inherit from another class, so why using the this pointer, it just makes the code look uglier.

Using the this* has nothing to do with inheritance in this case. It is required because the parameter and the member variable have the same names. The "this->" is to inform the compiler that the member variable is being accessed.

plus in the constructor you must initialize the integer values otherwise you may deal with some weird random numbers.

Yes member variables should usually be initialized in the constructor and in this program I might think about recommending a constructor that can initialize all the variables to user defined values.





> Then in my main class, I would want to use it like this(Omitting the login code for simplicity):
¿how did you do the login?
if you managed to obtain the nick and password from the file, then to get the other fields should be trivial

¿what do you need help with?
closed account (y3hk216C)
I login by obtaining the username and password from user input, then I go line by line using getline in a while loop and see if the username and password are on the same line in the file. Upon thinking about it when I use getline I save each line in a string variable named text, so I just have to tokenize each word in the string and then use the set functions to set up the object. I just think my brain has been fried from doing a lot of work haha.
User::User(){}//Default constructor bc im not sure how to fill the values with param

Perhaps something like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// You'll need to add the rest of the fields.
User::User(const std::string& user, int year_of_birth) : Name(user), birthYear(year_of_birth)
{
    // Blank body)
}

// In your "read" function:
...
   // Create the required variables for the current User.
   string user;
   int birth_year;

...
    // Read the data fr the current user.
    getline(input_stream, user, '\t');
    input_stream >> birth_year;

...
    // Create a User with the data you read above.
    User current_user(user, birth_year);
...


By the way if your "default" constructor doesn't do anything the don't create one or use the "default" keyword.


closed account (y3hk216C)
Ah ok thanks for the tip about constructors!
@jlb
1
2
3
4
5
6
7
8
9
10
11
12
struct S {
    int x, y;
};

class C {
    int x, y;
public:
    int GetX() const { return x; }
    int GetY() const { return y; }
    void SetX(int _x) { x = _x; }
    void SetY(int _y) { x = _x; }
};

I never said its necessary to use a struct, using a class with getters and setters only is a stupid idea not for a beginner but for an intermediate or expert, in his case a struct would be much simpler and in very few lines of code compared to a class in multiple lines of code witch is error prone and nasty, that's why I as an expert in c++ recommend it to beginners.

the code explains itself, except for the std::ifstream part, because I want him to do a small search and learn about it.
if you can't understand it then go to the tutorials sections on this website.

about the this pointer, why using inside a simple class, it will ust make the code ugly and larger.

The only reason I told him to initialize the integer values with -1 is to mark a default object as an invalid object if you see my code above

you have 4264 posts but there is much more for you to learn, I recommend getting The c++ programming language, good luck.
Last edited on
@ckh85222
hey buddy, before trying to write some more programs like this one, I recommend the c++ tutorials on this website, as you go through them one by one and in order, your knowledge of c++ with become better and better.
http://www.cplusplus.com/doc/tutorial/
If you have any question send me a private message I'll respond ASAP.
Last edited on
closed account (y3hk216C)
@fewdiefie Awesome thanks a ton I appreciate it!! I hope I can become proficient in this language with enough practice!
@ckh85222

Please be wary of people trying to draw you away from public discussion into PM's. This site has a history of trolls who maliciously give bad advice to programmers looking for help, and they often try and encourage the unwary to discuss code via PM so that other people on the forum can't see what they're doing and correct the things they're saying.

If you want help with code, it's always better to do it publicly in the forums. You're like to get help quicker, you'll get advice from a much wider variety of people, many of whom have years or decades of professional experience, and if any advice you recveive does have a mistake in, there's a better chance that someone else will catch it and correct it.
that's why I as an expert in c++ recommend it to beginners.

If you're such an expert why did you post such crappy code? For example your GetData() function has several instances of poor to bad practices:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

// IMO this function is doing too much. It really should just be getting the data, nothing else. 
UserData GetData(string username, const char* file)  // Why the char* instead of a std::string?
{
    ifstream infile; // Have you ever heard of RAII? This should really be "ifstream infile(file);"
    UserData tmp;
    infile.open(file);
    if (infile.fail())
        return UserData();    // failed to open file return an 'invalid' user // Why not just return tmp, instead of creating another "temporary" instance of your class.
    
    while (!infile.eof())  // Using eof() to control a read loop, really? You should be using the actual read instead.
    {
        infile >> tmp.firstName
                >> tmp.lastName
                >> tmp.birthYear
                >> tmp.number
                >> tmp.username
                >> tmp.password;

        if (tmp.username == username)
            return tmp;     // user found
    }
 
    infile.close();   // Again never heard of RAII? This is not needed since the stream goes out of scope when the function returns.
    return UserData();    // user not found return an 'invalid' user
}

@jlb
1st it is not crappy and you are being rude saying that, the code was meant to solve his problem only I wrote it without even thinking and you said it has many poor/bad practices, what are you talking about? your comments are crap. u just want my code to be like them, go suicide dude
Last edited on
@MikeyBoy
I told him to PM if he finds difficulties with the tutorials not code, please next time try to understand english then post your sloppy replies
Last edited on
Pages: 12