Creating new instances of a class

I have two classes with elements and relevant functions as follows:
1
2
3
4
5
class Network {
   public:
      vector<User> Users;

      void add_user(string name, int year, int zip);

1
2
3
4
5
void Network::add_user(string name, int year, int zip)
// Adds a user with given information
{
	Users.push_back(User(Users.size(), name, year, zip));
}

1
2
3
4
5
6
7
8
9
class User {
   public:
      int userID;
      string username;
      int birthyear;
      int zipcode;
      vector<int> friends;

      User(int ID, string name, int year, int zip);

1
2
3
4
5
6
7
User::User(int ID, string name, int year, int zip)
{
   userID = ID;
   username = name;
   birthyear = year;
   zipcode = zip;
}


I've gotten my program to work, except glitches with the User constructor.
When I create a User:
The ID field works fine.
The username field becomes like this: "username birthyear zipcode firstname" where the username is a two-word string and firstname is the first word there.

The birth year and zip code fields both become 1.

I've got no idea why this is happening at all, can anybody offer pointers?
Last edited on
Are you sure you are getting username correctly? From your results I guess you are probably using getline when your fields are space separated. If that's the case you will have to parse it yourself somehow (like read two space separated fields and join them).
It's so far working fine for me. There shouldn't be any problems with the constructor and Network::add_user() works fine.

Maybe could you please provide the code which calls the constructor?
This is what I'm doing with the input:
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
// Usage for choice1: '1 FirstName LastName BirthYear ZipCode'

string input, str1, str2, str3, str4;
str1.clear(); str2.clear(); str3.clear(); str4.clear(); // To clear from previous iterations of
int choice = 0;                                                        // a while loop
getline(cin, input);
stringstream convert(input);
convert >> choice;                 // Puts only first character of "input" into an int (choice)

// Split input into individual strings
int numarg = 1;  // Minimum number. I assume that there's no input error
int lastspace = 0; // by the user - which, for my purposes, is safe
int space = 0;

for (unsigned int i = 0; i < input.length(); i++) {
   if (input[i] == ' ') {
      numarg++;
      if (!lastspace && !space) {
         lastspace = space = i;    // If it hasn't iterated at all, they'll both set to the first space
      }                                        // at input[1] - it's possible that this is a small problem
      else {
         space = i;                       // If lastspace is already set, only move space forward
      }                                        // for use below

      if (numarg == 2) {
         str1.assign(input, lastspace + 1, space - (lastspace + 1));
      }
      else if (numarg == 3) {
         str2.assign(input, lastspace + 1, space - (lastspace + 1));
      }
      else if (numarg == 4) {
         str3.assign(input, lastspace + 1, space - (lastspace + 1));
      }
      else if (numarg == 5) {
         str4.assign(input, lastspace + 1, space - (lastspace + 1));
      }
   lastspace = space;
   }
}

   if (choice == 1) {				// Add user
      if (numarg != 5) {      // It never gets caught here
         cout << "\tError: Incorrect number of arguments." << endl;
      }
      else {
         string name = string(str1) + string(str2);  // Creates name in single string
         int year, zip;      // Temporary
         stringstream birthyear(input);
         birthyear >> year;
         stringstream zipcode(input);
         zipcode >> zip;
         Network.add_user(name, year, zip);
      }
   }


I know it's probably not the optimal way of doing it, but I'm happy with it if it works at all, so that's not an issue in this case.
Last edited on
@theranga, all commands related to the constructor:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Network.add_user(name,year,zip); // Line 52 above
             // Which leads to...

void Network::add_user(string name, int year, int zip)
{
	Users.push_back(User(Users.size(), name, year, zip));
}
            // Which leads to...

User::User(int ID, string name, int year, int zip)
{
   userID = ID;
   username = name;
   birthyear = year;
   zipcode = zip;
}
Last edited on
Possible fix? I just thought of this, but I think it would just be adding an unnecessary step, and not solving the problem.
Anyway,
In Network::add_user(), could I create a temporary User object, initialize its fields with User::User() the input arguments, then do Users.push_back(tempUserObject)
i think the problem is a couple of lines before that

on lines 48 and 50, birthyear and zipcode are both initialised to input.

shouldn't it be
stringstream birthyear (str3);
and
stringstream zipcode (str4);?
You are right about that! Thanks. But that doesn't seem to fix the username issue.

When I run the program, and put this line in:
cout << Network.Users[0].username << endl;
the output is:
first last 1981 90007first
Last edited on
I don't really understand the problem (not to say there isn't one!), but it seems that to get your username you concatenate the first and last names.

is the problem that the username created is "usernameLastname" rather than "username lastname"?
I did concatenate them (now that I look at it, I missed putting a space in between). The problem is that the username created is formatted like "firstName Lastname birthYear zipCodefirstName" and that's what has me dumbfounded

EDIT: I just put in a space.
string name = string(str1) + string(" ") + string(str2);
The output for "username" now reads:
firstName Lastname birthYear zipCode firstName
(the difference is the space between zipCode and firstName)
It seems that str1 never gets separated into only the first word (after the number 1)

EDIT 2.0: Or that my system of splitting up the strings doesn't work at all.
It is most definitely the first string only. However, something interesting: when I cout each string, I get:
1
2
3
4
String 1: firstname lastname 1981 90007
String 2: firstname
String 3: lastname
String 4: 1981


This makes me believe either my for loop iterates at the wrong times, or my assignment into the strings is wrong.
Last edited on
the problem is in the bit which splits up the strings. from line 11 it should look 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
34
35
    int numarg = 0;  // Minimum number. I assume that there's no input error
    int lastspace = -1; // -1 because if you plug lastspace=0 into the assign functions below then it drops the 1st character
    int space = 0;

    for (unsigned int i = 0; i < input.length(); i++)
    {
        if (input[i] == ' ')
        {
            numarg++;
            
            space=i;

            if (numarg == 2)
            {
                str1.assign(input, lastspace + 1, space - (lastspace + 1));
                cout << "str1: " << str1 << endl;
            }
            else if (numarg == 3)
            {
                str2.assign(input, lastspace + 1, space - (lastspace + 1));
                cout << "str2: " << str2 << endl;
            }
            else if (numarg == 4)
            {
                str3.assign(input, lastspace + 1, space - (lastspace + 1));
                cout << "str3: " << str3 << endl;
            }
            else if (numarg == 5)
            {
                str4.assign(input, lastspace + 1, space - (lastspace + 1));
                cout << "str4: " << str4 << endl;
            }
            lastspace = space;
        }
    }


the problem was twofold - numarg is treated as the 'argument number' that you have just passed - ie it only changes once you reach the end of an argument. Thus, it should have been set to 0. Secondly, by, setting lastspace=space, the 3rd argument of str2.assign(...,...,space-(lastspace+1)) became -1.

-1 is commonly used by compilers as a value for string::npos - a value which basically represents the maximum length of a string and is also used to mean 'to the end of the string'.

Because of these two problems, when the loop reached the 1st space it set numarg to 2 and then set str2 to everything from the 1st space to the end of the string.

After that it ran fine, but because numarg was 1 ahead of where it was supposed to be, lastname was set to firstname, birthyear was set to firstname, and so on.
That makes perfect sense. It works fine, except str4 never shows up now, because numarg never makes it to 5. Also, using the iterator i instead of space works.
Last edited on
to fix that problem, put
if (lastspace<input.length()-1) str4.assign(input,lastspace+1,string::npos);
after the loop.
That problem comes up because the loop doesn't treat the end of the string as a space. all this does is grabs the bit between the last space and the end and copies it into str4.
The if is to make sure that there is actually something to copy.
Because lastspace constantly updates with i, that won't work. After a little tinkering, I found that this works:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
	int numarg = 0;
	int lastspace = -1;

	for (unsigned int i = 0; i < input.length(); i++) {
		if (input[i] == ' ') {
			numarg++;
			if (numarg == 2) {
				str1.assign(input, lastspace + 1, i - (lastspace + 1));
				cout << "str1: " << str1 << endl;
			}
			else if (numarg == 3) {
				str2.assign(input, lastspace + 1, i - (lastspace + 1));
			  cout << "str2: " << str2 << endl;
			}
			else if (numarg == 4) {
				str3.assign(input, lastspace + 1, i - (lastspace + 1));
				cout << "str3: " << str3 << endl;
				numarg++;
				str4.assign(input, i + 1, input.length() - i);
				cout << "str4: " << str4 << endl;
			}
			lastspace = i;
		}
	}


I need to use numarg to error-check later, so incrementing it again in the numarg==4 case solves that, and I'm happy with how this works.

Thank you SO much for your help!
no problems
Topic archived. No new replies allowed.