如何将字符串读入类C ++类

时间:2017-05-09 21:58:04

标签: c++ arrays

我有一个来自我创建的视频类的DVD数组

Video dvd[10];

每个视频都有属性

class Video {
    string _title;
    string _genre;
    int _available;
    int _holds;
public:
    Video(string title, string genre, int available, int holds);
    Video();
    void print();
    void read(istream & is, Video dvd);
    int holds();
    void restock(int num);
    string getTitle();
    ~Video();
};

我正在尝试用我的文本文件中的数据填充此数组,其中每个信息(例如标题和流派)都用逗号分隔

Legend of the seeker, Fantasy/Adventure, 3, 2
Mindy Project, Comedy, 10, 3
Orange is the new black, Drama/Comedy, 10, 9

我尝试过使用 getline(in,line,',')但我的大脑在将每一行插入dvd数组时停止了。

我还创建了一个读取方法来读取由空格分隔的每个单词,但我认为这不是我真正想要的。

我还尝试用getline读取一行,将该行存储在一个字符串中并从那里拆分,但我对此感到困惑。

**我可以从每一行获得我需要的字符串,我的困惑在于如何在while循环中将它插入到我的类数组中,尤其是当我一次只能读取一个单词时。

我需要帮助我应该采取什么方法来解决这个问题。

**我的代码

#include <iostream>
#include <fstream>
#include <cassert>
#include <vector>

#define MAX 10

using namespace std;

class Video {
    string _title;
    string _genre;
    int _available;
    int _holds;
public:
    Video(string title, string genre, int available, int holds);
    Video();
    void print();
    void read(istream & is, Video dvd);
    int holds();
    void restock(int num);
    string getTitle();
    ~Video();
};

Video::Video(string title, string genre, int available, int holds){
    _title = title;
    _genre = genre;
    _available = available;
    _holds = holds;
}

void Video::read (istream & is, Video dvd)   
{  
    is >> _title >> _genre >> _available>>_holds;
    dvd = Video(_title,_genre,_available,_holds);

}

int Video::holds(){
    return _holds;
}

void Video::restock(int num){
    _available += 5;
}

string Video::getTitle(){
    return _title;
}

Video::Video(){

}

void Video::print(){
    cout<<"Video title: " <<_title<<"\n"<<
    "Genre: "<<_genre<<"\n"<<
    "Available: " <<_available<<"\n"<<
    "Holds: " <<_holds<<endl;
}

Video::~Video(){
    cout<<"DESTRUCTOR ACTIVATED"<<endl;
}

int main(int params, char **argv){

    string line;
    int index = 0;
    vector<string> tokens;
    //Video dvd = Video("23 Jump Street", "comedy", 10, 3);
    //dvd.print();
    Video dvd[MAX];
    dvd[0].holds();

    ifstream in("input.txt");

    /*while (getline(in, line, ',')) {
        tokens.push_back(line);

    }
    for (int i = 0; i < 40; ++i)
    {
        cout<<tokens[i]<<endl;
    }*/

    if(!in.fail()){
        while (getline(in, line)) {

            dvd[index].read(in, dvd[index]);
            /*cout<<line<<endl;
            token = line;
            while (getline(line, token, ',')){

            }
            cout<<"LINE CUT@@@@@"<<endl;
            cout<<line<<endl;
            cout<<"TOKEN CUT@@@@@"<<endl;*/
            //dvd[index] = 
            index++;
        }
    }else{
        cout<<"Invalid file"<<endl;
    }


    for (int i = 0; i < MAX; ++i)
    {
        dvd[i].print();
    }


}

1 个答案:

答案 0 :(得分:1)

首先,我会将Video::read函数更改为operator >>的重载。这将允许Video类在使用输入流时像其他任何类型一样使用。

此外,将read实现为返回void的非静态成员函数的方式并不直观,而且非常使用起来很笨拙。你会如何编写循环,同时检测到你已经到达文件的末尾(想象一下,如果只有3个项目可读 - 你怎么知道不尝试读取第四个项目)?在C ++中执行此操作的更好,直观,坦率,事实上的方法是重载>>运算符。

(最后,我展示了如何编写使用重载read)的>>函数

class Video
{
   //...
   public:
      friend std::istream& operator >> (std::istream& is, Video& vid);
   //..
};

我不会过去为什么这应该是friend函数,因为这里可以很容易地研究如何重载>>

所以我们需要实现这个功能。以下是一个读取单行的实现,并将信息复制到传入的vid

std::istream& operator >> (std::istream& is, Video& vid)
{
    std::string line;
    std::string theTitle, theGenre, theAvail, theHolds;

    // First, we read the entire line
    if (std::getline(is, line))
    {
        // Now we copy the line into a string stream and break 
        // down the individual items
        std::istringstream iss(line);

        // first item is the title, genre, available, and holds
        std::getline(iss, theTitle, ',');
        std::getline(iss, theGenre, ',');
        std::getline(iss, theAvail, ',');
        std::getline(iss, theHolds, ',');

       // now we can create a Video and copy it to vid
       vid = Video(theTitle, theGenre, 
                   std::stoi(theAvail), // need to change to integer
                   std::stoi(theHolds)); // same here
    }
    return is;  // return the input stream
}

注意vid是一个引用参数,不是通过值传递的。您的read函数,如果您要保留它,则需要进行相同的更改。

我们上面所做的是我们首先使用对std::getline的“外部”调用来读取整行。一旦我们将该行作为字符串,我们使用std::istringstream分解该字符串,并使用getline调用的istringstream调用分隔逗号上的每个项目。Video }。然后,我们只需从我们从istringstream检索到的信息中创建一个临时vid,然后将其复制到main

这是一个int main() { Video dvd[10]; int i = 0; while (i < 10 && std::cin >> dvd[i]) { dvd[i].print(); ++i; } } 函数,现在最多可读取10个项目:

cin >> dvd[i]

因此,如果你看一下循环,我们所做的只是1)确保我们不要超过10个项目,2)只使用>>,这看起来就像你{{1}的日常使用输入项目时。这是>>重载Video的神奇之处。

Here is a live example, using your data

如果您打算保留read函数,那么如果您将返回类型更改为bool,如果项目已被读取或true,则返回false会更容易}否则,只需调用operator >>

以下是一个例子:

bool Video::read(std::istream & is, Video& dvd)
{
    if (is.good())
    {
        is >> dvd;
        return true;
    }
    return false;
}

这是main函数:

int main()
{
    Video dvd[10];
    int i = 0;
    while (i < 10 && dvd[i].read(std::cin, dvd[i]))
    {
        dvd[i].print();
        ++i;
    }
}

Live Example #2

但是,我仍然说Video::read使用非静态成员会使main中的代码变得笨拙。