2

I was wondering if enumeration is commonly used with user input. I'm doing an exercise in which in my Book class I have to create an enum Genre with different genre enumerators such as fiction, non, fiction etc.

When the user uses the program, he/she is asked for certain information about the book being stored. For a genre, normally I would just do this with a string function and restrict it to certain names with if statements.

However, I'm not sure how to accomplish the same process with an enumerated type, nor do I know if it's even supposed to be used for that sort of thing. Here is the code if you're interested.

#include "std_lib_facilities.h"

//Classes-----------------------------------------------------------------------

class Book{
public:
       Book(){}; // default constructor
       //operators
       friend ostream& operator<<(ostream& out, const Book& val);
       bool Book::operator==(const Book& check)
       //enumerators
       enum Genre{
            fiction, nonfiction, periodical, biography, children};
       //member functions
       string title();
       string author();
       int copyright();
       void ISBN();
       bool checkout();
private:
        string title_;
        string author_;
        int copyright_;
        int ISBN1;
        int ISBN2;
        int ISBN3;
        char ISBN4;
        bool checkout_;
};

// Error Function---------------------------------------------------------------

void _error(const string& s)
{
     cout << endl;
     cout << "Error: " << s << endl;
     cout << endl;
}

// Member Functions-------------------------------------------------------------

string Book::title()
{
       cout << "Title: ";
       getline(cin,title_);
       cout << endl;
       return title_;
}

string Book::author()
{
       cout << "Author: ";
       getline(cin,author_);
       cout << endl;
       return author_;
}

int Book::copyright()
{
    cout << "Copyright: ";
    cin >> copyright_;
    cout << endl;
    return copyright_;
}

void Book::ISBN()
{
     cout << "ISBN (Use spaces): ";
     cin >> ISBN1 >> ISBN2 >> ISBN3 >> ISBN4;
     if((ISBN1<0) || (ISBN2<0) || (ISBN3<0) || (ISBN1>9) || (ISBN2>9) || (ISBN3)>9)
               _error("Must be single digit.");
     else if(!isdigit(ISBN4) && !isalpha(ISBN4))
               _error("Must be single digit or letter.");
     else{ cout << endl;
           return;}
}

bool Book::checkout()
{
     char check;
     cout << "Checked out?(Y or N): ";
     cin >> check;
     switch(check){
     case 'Y':
          cout << endl;
          return true;
          break;
     case 'N':
          cout << endl;
          return false;
          break;
     default: 
              _error("Must be Y or N.");}
}

// Operator Overloads-----------------------------------------------------------

ostream& operator<<(ostream& out, const Book& val){
         out << "Title: " << val.title_ << endl;
         out << "Author: " << val.author_ << endl;
         out << "ISBN: " << val.ISBN1 << "-" << val.ISBN2 << "-" << val.ISBN3 << "-" << val.ISBN4 << endl;
         out << endl;
         return out;}

bool Book::operator==(const Book& check){
     return((ISBN1 == check.ISBN1) && (ISBN2 == check.ISBN2) && (ISBN3 == check.ISBN3)
             && (ISBN4 == check.ISBN4));}

// Main-------------------------------------------------------------------------   

int main()
{
    bool finished = false;
    char notfinished;
    while(!finished)
    {
      Book book;
      book.title();
      book.author();
      book.copyright();
      book.ISBN();
      book.checkout();
      cout << "Do you wish to store another book?(Y or N): ";
      cin >> notfinished;
      if(notfinished == 'Y'){ 
                     cin.ignore();
                     cout << endl;}
      else if(notfinished == 'N') finished = true;
      else _error("Must be Y or N");
      }
     keep_window_open();
     }

Note that some things aren't being used at the moment because the feature they are a part of hasn't been fully implemented yet (storing in a library, outputting books, etc.)

So what would it take to accept user input for the enumerators listed, if even possible? I was thinking something along the lines of making a Genre variable. Then having a function where the user inputs for cin>>variable. However, I'm guessing that the function wouldn't understand an input like 'fiction' and would only accept the enumerator values and input.

trikker
  • 2,651
  • 10
  • 41
  • 57

3 Answers3

1

Make Genre a class that wraps the enum type (GenreTypeEnum). Add the necessary operators, e.g. istream, ostream, equal operator, etc.

Inside the istream operator, you can read a std::string from the stream and then parse and convert the value to the associated GenreTypeEnum.

Something like this perhaps:

    namespace GenreType { enum GenreTypeEnum { miscellaneous, fiction, non_fiction, children }; }

    class Genre
    {
      public:
        Genre() : genreType( GenreType::miscellaneous) {}
        ~Genre() {}

        void setType( std::string genreTypeString ){ // implement string-> enum }
        std::string toString( void ) const { // convert genre back to string }

      private:

        GenreType::GenreTypeEnum genreType;

    };

    std::ostream& operator<<( std::ostream& os, const Genre& genre )
    {
        os << genre.toString();
        return os;
    }

    std::istream& operator>>( std::istream& is, Genre& genre )
    {
        std::string input;
        is >> input;

        genre.setType( input );
        return is;
    }
oz10
  • 153,307
  • 27
  • 93
  • 128
0

C-style enums are not terribly useful for this purpose, since there's no way to recover the original string name. You could make some switch-based mechanism, but at that point you may as well just set up your own way of doing it all that works with your user I/O requirements without shoehorning.

chaos
  • 122,029
  • 33
  • 303
  • 309
  • So would they only be useful if I were storing data directly in the program through passing arguments such as book(Genre::fiction)? – trikker Jul 19 '09 at 02:51
  • Yeah. The sort of switch-based mechanism I mentioned would be for translating strings back and forth with `Genre::whatever` values. – chaos Jul 19 '09 at 02:53
  • Hmmm..okay thanks. If you don't mind could you post a short psuedo code example of what you mean by a switch based mechanism? I still don't really get how it could work with a string. – trikker Jul 19 '09 at 02:59
  • The switch part would be for producing a string, i.e. `string genreName(int enum_value) { case Genre::fiction: return "fiction"; }`. Translating the input string to an enum value would be yet more of a pain. – chaos Jul 19 '09 at 03:02
0

One of the ways to handle this is to set up a map of strings to enum values. Other possibilities include a dedicated function.

See this question for some ideas.

This question has some ideas of how to generate code to convert enums to strings, but most of the examples will work in reverse as well.

Community
  • 1
  • 1
Eclipse
  • 44,851
  • 20
  • 112
  • 171