I'm glad I got that about right.
You said:
I hadn't thought that the vector needed to be of pointers to instances of users. |
It doesn't
have to be, but I have reason for it.
In case you have never thought about this:
When you store objects in a vector directly, and then a push_back() operation causes a reallocation of storage space for the vector all existing objects are moved to new memory locations.
Problem: We are storing pointers to users in each users friends vector.
When the users move in memory, all pointers to them become invalid.
This is a disaster.
When pointers to objects are stored, the pointers themselves will be moved in memory on reallocation,
but their values, ie. the addresses they point to, will remain unchanged. All pointers to users already handed out remain valid.
EDIT: I forgot to answer your question.
If I do make it a class, does there need to be both a struct and a class? Or would I just move all the fields of the user struct into the class?
|
There is no struct and some separate class! The user structure is it!
When I said you might make it a class I meant thet it could be changed from
struct user;
to
class user;
instead.
I may post back with things developed this way a bit more, so you can see.
EDIT2:
OK. I have turned user into a class and have converted the make_friends() and list_friends() to member functions of the user class.
I also added friends for poor friendless Bob and Ann, so the output is a little different:
Note how the code for calling the functions in main() is different, since they are user class member functions now.
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 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
|
#include <iostream>
#include <vector>
using namespace std;
class user
{
public:
// int id;
string name;
int birthyear;
int zipcode;
vector<user*> friends;
// functions
bool make_friends( user* p_u );
bool list_friends(void);
// ctor
user(string Name, int year, int zip): name(Name), birthyear(year), zipcode(zip) {}
};
bool user::make_friends( user* p_u )
{
// add a check here to see if these two are already friends.
// if so, return false here (don't add same friend twice)
// OK - in the clear
friends.push_back( p_u );// p_u is now on my friend list
p_u->friends.push_back( this );// I assume that should be mutual
return true;
}
bool user::list_friends(void)
{
cout << name << "'s friends are: ";
if( friends.size() == 0 )
{
cout << name << " has no friends! " << endl;
return false;
}
for( unsigned i = 0; i < friends.size(); ++i)
cout << friends[i]->name << " ";
cout << endl;
return true;
}
//** end of user class member function definitions ***
// We still have one global function
void list_all_names( const vector<user*>& p_users )
{
if( p_users.size() == 0 )
{
cout << " There are no users! " << endl;
return;
}
cout << "The list of user names is:" << endl;
for( unsigned i = 0; i < p_users.size(); ++i )
cout << p_users[i]->name << endl;
cout << endl;
return;
}
int main()
{
vector<user*> Users;// a users id = his address in memory
// add some users
Users.push_back( new user("Joe", 1984, 91006) );// 0
Users.push_back( new user("Bob", 2001, 90678) );// 1
Users.push_back( new user("Sally", 1993, 41266) );// 2
Users.push_back( new user("Ann", 1945, 22314) );// 3
Users.push_back( new user("Frank", 1972, 43682) );// 4
// I'll list them for you now
list_all_names( Users );
// Lets make Joe, Sally and Frank all friends, shall we?
Users[0]->make_friends( Users[2] );// Joe makes friends with Sally
Users[0]->make_friends( Users[4] );// Joe makes friends with Frank
Users[2]->make_friends( Users[4] );// Sally makes friends with Frank
// Poor Bob and Ann deserve at least onr friend. How about each other?
Users[1]->make_friends( Users[3] );// Bob makes friends with Ann
// Lets check that by listing everyones friends
for( unsigned i = 0; i < Users.size(); ++i )
Users[i]->list_friends();
cout << endl;
return 0;
}
|
Output:
The list of user names is:
Joe
Bob
Sally
Ann
Frank
Joe's friends are: Sally Frank
Bob's friends are: Ann
Sally's friends are: Joe Frank
Ann's friends are: Bob
Frank's friends are: Joe Sally
|
EDIT3: Sorry, I keep adding more stuff to this!
Add these two weird functions after line 50 in the above code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
// a couple of special tools
struct userRank// defines what userA < userB means, so they can be ranked, sorted, etc,,,
{
// user p_u1 goes before p_u2 on a ranking list if p_u1 has more friends
bool operator()( const user* p_u1, const user* p_u2 )
{
return p_u2->friends.size() < p_u1->friends.size();
}
};
// defines what ostream << user means ( so we can do: cout << Users[i]; and a custom description will appear )
ostream& operator<<( ostream& os, const user& ru )
{
os << "Name: " << ru.name << '\n';
os << "Birth year: " << ru.birthyear << '\n';
os << "zipcode: " << ru.zipcode << '\n';
os << "I have " << ru.friends.size() << " friends." << '\n';
return os;
}
|
Then add this code to main() after line 93 and add
#include<algorithm>
at the top:
1 2 3 4 5 6 7 8 9 10 11 12 13
|
// sort users by popularity
userRank ur;
sort( Users.begin(), Users.end(), ur );
// Are those with the most friends listed first?
cout << endl;
for( unsigned i = 0; i < Users.size(); ++i )
Users[i]->list_friends();
// Listing everyones full user data
cout << endl << "All data for our full user base:" << endl;
for( unsigned i = 0; i < Users.size(); ++i )
cout << *Users[i] << endl;
|
New output:
The list of user names is:
Joe
Bob
Sally
Ann
Frank
Joe's friends are: Sally Frank
Bob's friends are: Ann Frank
Sally's friends are: Joe Frank
Ann's friends are: Bob
Frank's friends are: Joe Sally Bob
Frank's friends are: Joe Sally Bob
Joe's friends are: Sally Frank
Bob's friends are: Ann Frank
Sally's friends are: Joe Frank
Ann's friends are: Bob
All data for our full user base:
Name: Frank
Birth year: 1972
zipcode: 43682
I have 3 friends.
Name: Joe
Birth year: 1984
zipcode: 91006
I have 2 friends.
Name: Bob
Birth year: 2001
zipcode: 90678
I have 2 friends.
Name: Sally
Birth year: 1993
zipcode: 41266
I have 2 friends.
Name: Ann
Birth year: 1945
zipcode: 22314
I have 1 friends.
|