【问题标题】:Enumerations and User Input枚举和用户输入
【发布时间】:2009-07-19 02:38:54
【问题描述】:

我想知道枚举是否常用于用户输入。我正在做一个练习,在我的 Book 课程中,我必须创建一个枚举类型,其中包含不同类型的枚举器,例如小说、非小说、小说等。

当用户使用该程序时,系统会要求他/她提供有关所存储图书的某些信息。对于一种类型,通常我会使用字符串函数来执行此操作,并使用 if 语句将其限制为某些名称。

但是,我不确定如何使用枚举类型完成相同的过程,也不知道它是否应该用于那种事情。如果你有兴趣,这里是代码。

#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();
     }

请注意,有些东西目前没有被使用,因为它们所属的功能尚未完全实现(存储在图书馆、输出书籍等)

那么,如果可能的话,如何接受用户输入列出的枚举数?我在想一些类似于制作流派变量的东西。然后具有用户输入 cin>>variable 的功能。但是,我猜测该函数不会理解像“小说”这样的输入,并且只会接受枚举值和输入。

【问题讨论】:

    标签: c++


    【解决方案1】:

    使 Genre 成为一个封装枚举类型 (GenreTypeEnum) 的类。添加必要的运算符,例如istream、ostream、等号运算符等

    在 istream 运算符中,您可以从流中读取 std::string,然后解析该值并将其转换为关联的 GenreTypeEnum。

    可能是这样的:

        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;
        }
    

    【讨论】:

      【解决方案2】:

      C 风格的枚举对于这个目的并不是非常有用,因为没有办法恢复原始字符串名称。您可以创建一些基于 switch 的机制,但此时您也可以设置自己的方式来满足您的用户 I/O 要求,而无需强加。

      【讨论】:

      • 那么只有当我通过传递诸如 book(Genre::fiction) 之类的参数将数据直接存储在程序中时,它们才会有用吗?
      • 是的。我提到的那种基于开关的机制是用Genre::whatever 值来回转换字符串。
      • 嗯..好的,谢谢。如果您不介意,您能否发布一个简短的伪代码示例,说明您所说的基于开关的机制是什么意思?我仍然不明白它如何与字符串一起工作。
      • 开关部分用于生成字符串,即string genreName(int enum_value) { case Genre::fiction: return "fiction"; }。将输入字符串转换为枚举值会更加痛苦。
      【解决方案3】:

      处理此问题的方法之一是设置字符串到枚举值的映射。其他可能性包括专用功能。

      请参阅此question 了解一些想法。

      This question 对如何生成代码以将枚举转换为字符串有一些想法,但大多数示例也可以反过来工作。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-04-26
        • 2018-08-12
        • 1970-01-01
        • 2019-03-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多