I l@ve RuBoard Previous Section Next Section

Exercise 4.4

A user profile consists of a login, the actual user name, the number of times logged on, the number of guesses made, the number of correct guesses, the current level ?one of beginner, intermediate, advanced, guru ?and the percentage correct (this latter may be computed or stored). Provide a UserProfile class. Support input and output, equality and inequality. The constructors should allow for a default user level and default login name of "guest." How might you guarantee that each guest login for a particular session is unique?



class UserProfile { 


public: 


    enum uLevel { Beginner, Intermediate, Advanced, Guru }; 





    UserProfile( string login, uLevel = Beginner ); 


    UserProfile(); 





    // default memberwise initialization and copy sufficient 


    // no explicit copy constructor or copy assignment operator 


    // no destructor necessary ... 





    bool operator==( const UserProfile& ); 


    bool operator!=( const UserProfile &rhs ); 





    // read access functions 


    string login() const { return _login; } 


    string user_name() const { return _user_name; } 


    int login_count() const { return _times_logged; } 


    int guess_count() const { return _guesses; } 


    int guess_correct() const { return _correct_guesses; } 


    double guess_average() const; 


    string level() const; 





    // write access functions 


    void reset_login( const string &val ){ _login = val; } 


    void user_name( const string &val ){ _user_name = val; } 





    void reset_level( const string& ); 


    void reset_level( uLevel newlevel ) { _user_level = newlevel; } 





    void reset_login_count( int val ){ _times_logged = val; } 


    void reset_guess_count( int val ){ _guesses = val; } 


    void reset_guess_correct( int val ){ _correct_guesses = val; } 





    void bump_login_count( int cnt=1 ){ _times_logged += cnt; } 


    void bump_guess_count( int cnt=1 ){ _guesses += cnt; } 


    void bump_guess_correct(int cnt=1){ _correct_guesses += cnt;} 





 private: 


    string _login; 


    string _user_name; 


    int    _times_logged; 


    int    _guesses; 


    int    _correct_guesses; 


    uLevel _user_level; 





    static map<string,uLevel> _level_map; 


    static void init_level_map(); 


    static string guest_login(); 


}; 





inline double UserProfile::guess_average() const 


{ 


   return _guesses 


         ? double(_correct_guesses) / double(_guesses) * 100 


         : 0.0; 


} 





inline UserProfile::UserProfile( string login, uLevel level ) 


    : _login( login ),   _user_level( level ), 


      _times_logged( 1 ), _guesses( 0 ), _correct_guesses( 0 ){} 





#include <cstdlib> 





inline UserProfile::UserProfile() 


    : _login( "guest" ), _user_level( Beginner ), 


      _times_logged( 1 ), _guesses( 0 ), _correct_guesses( 0 ) 


{ 


   static int id = 0; 


   char buffer[ 16 ]; 





   // _itoa() is a Standard C library function 


   // turns an integer into an ascii representation 


      _itoa( id++, buffer, 10 ); 





   // add a unique id during session to guest login 


   _login += buffer; 


} 





inline bool UserProfile:: 


operator==( const UserProfile &rhs ) 


{ 


     if ( _login == rhs._login && 


          _user_name == rhs._user_name ) 


               return true; 


     return false; 


} 





inline bool UserProfile:: 


operator !=( const UserProfile &rhs ){ return ! ( *this == rhs ); } 





inline string UserProfile::level() const { 


    static string _level_table[] = { 


           "Beginner", "Intermediate", "Advanced", "Guru" }; 


    return _level_table[ _user_level ]; 


} 





ostream& operator<<( ostream &os, const UserProfile &rhs ) 


{ // output of the form: stanl Beginner 12 100 10 10% 


     os << rhs.login() << ' ' 


        << rhs.level() << ' ' 


        << rhs.login_count() << ' ' 


        << rhs.guess_count() << ' ' 


        << rhs.guess_correct() << ' ' 


        << rhs.guess_average() << endl; 


   return os; 


} 





// overkill ... but it allows a demonstration ... 


map<string,UserProfile::uLevel> UserProfile::_level_map; 





void UserProfile::init_level_map(){ 


    _level_map[ "Beginner" ] = Beginner; 


    _level_map[ "Intermediate" ] = Intermediate; 


    _level_map[ "Advanced" ] = Advanced; 


    _level_map[ "Guru" ] = Guru; 


} 





inline void UserProfile::reset_level( const string &level ){ 


     map<string,uLevel>::iterator it; 


     if ( _level_map.empty() ) 


          init_level_map(); 





     // confirm level is a recognized user level ... 


     _user_level = 


         (( it = _level_map.find( level )) != _level_map.end() ) 


               ? it->second : Beginner; 


} 





istream& operator>>( istream &is, UserProfile &rhs ) 


{   // yes, this assumes the input is valid ... 


    string login, level; 


    is >> login >> level; 





    int lcount, gcount, gcorrect; 


    is >> lcount >> gcount >> gcorrect; 


    rhs.reset_login( login ); 


    rhs.reset_level( level ); 





    rhs.reset_login_count( lcount ); 


    rhs.reset_guess_count( gcount ); 


    rhs.reset_guess_correct( gcorrect ); 





    return is; 


} 

Here is a small program to exercise our UserProfile class:



int main() 


{ 


   UserProfile anon; 


   cout << anon; // test out output operator 





   UserProfile anon_too; // to see if we get unique id 


   cout << anon_too; 





   UserProfile anna( "AnnaL", UserProfile::Guru ); 


   cout << anna; 





   anna.bump_guess_count( 27 ); 


   anna.bump_guess_correct( 25 ); 


   anna.bump_login_count(); 


   cout << anna; 





   cin >> anon; // test out input operator 


   cout << anon; 


} 

When compiled and executed, this program generates the following output (my responses are highlighted in bold):



guest0 Beginner 1 0 0 0 


guest1 Beginner 1 0 0 0 


AnnaL Guru 1 0 0 0 


AnnaL Guru 2 27 25 92.5926 


robin Intermediate 1 8 3 


robin Intermediate 1 8 3 37.5 
    I l@ve RuBoard Previous Section Next Section