如何通过一个循环将多个文件的内容分配给不同的类属性?

时间:2019-12-30 20:31:58

标签: c++

我有三个不同的文本文件,分别来自命令行,分别为 a.txt b.txt c.txt 。我还有三个类,分别称为 class A class B class C 。每个类对应于每个文件。例如,“ a.txt”包含:

12 title1
15 title2
20 title3

其中第一列是“ id”,第二列是标题(在每一行中,id和标题之间都有一个空格)。与此文件对应的是A类,其头文件类似于:

class A {
public:
    A();

    // the id doesn't need to be int
    A(const string &id, const string &title);

    void setId(const string &id);

    void setTitle(const string &title);

private:
    string id_;
    string title_;
};

程序应从命令行获取参数(即文件),读取每个文件的内容并提取其内容以分配相应类的变量。按照上面的示例,程序通过setID应当为a1.id_分配“ 12”,并且通过setTitle来为a1.title_分配“ title1”,而对于其他两个实例,则相同。是否可以仅通过一个效率循环就所有文件和类进行所有提及的作业?无论哪种情况(无论可能与否),建议的解决方案是什么?

修改 为每个类创建这么多不同名称的变量根本不符合成本效益

1 个答案:

答案 0 :(得分:1)

我们将所有数据存储在一个容器中。为此,我们需要一个可以增长的动态容器。 std::vector是必经之路。

为使此代码高效,我们将覆盖类A的插入器和提取器运算符。插入器将简单地将ID和Title插入输出流。容易理解。

提取器稍微复杂些,但也易于理解。我们首先使用标准的“ >>”操作提取ID。然后,我们用std::getline读取了该行的其余部分,因为标题可能包含空格。这将是“ >>”运算符的定界符。请注意,std::getline将读取前导/尾随空格。也许您需要“修剪”您的标题字符串。

主要,我们只是循环浏览命令行参数,然后为每个参数打开文件。如果可以打开它,我们将使用std::copy将文件的所有行(即完整内容)复制到A类型的std::vector中。

std::istream_terator将逐行调用A类的重写提取程序运算符,直到文件结束。 std::back_inserter会将读取的A实例“推回”到向量中。

在主体的最后,我们显示了A向量的完整内容。

请参阅:

#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
#include <vector>
#include <iterator>
#include <algorithm>

class A {
public:
    // Constructors
    A() : id_(), title_() {}
    A(const std::string& id, const std::string& title) : id_(id), title_(title) {}

    // Setters
    void setId(const std::string& id) { id_ = id; }
    void setTitle(const std::string& title) { title_ = title; }

    // Overwrite extractor for easier reading
    friend std::istream& operator >> (std::istream& is, A& a) {
        if (std::string id{}, title{}; is >> id && getline(is, title)) {
            a.id_ = id; a.title_ = title;
        }
        return is;
    }
    // Overwrite inserter for easier writing
    friend std::ostream& operator << (std::ostream& os, const A& a) {
        return os << "Id: " << std::setw(5) << a.id_ << "   Title: " << a.title_ << "\n";
    }
private:
    std::string id_{};
    std::string title_{};
};


int main(int argc, char* argv[]) {

    // Here we will store all read data
    std::vector<A> data{};

    // Work on all command line arguments
    for (size_t fileNumber = 1; fileNumber < argc; ++fileNumber) {

        // Open the corresponding file and check, if it is open
        if (std::ifstream ifs(argv[fileNumber]); ifs) {

            // Copy all data from this file into the class and the vector 
            std::copy(std::istream_iterator<A>(ifs), {}, std::back_inserter(data));
        }
    }

    // Show the result on the screen
    std::copy(data.begin(), data.end(), std::ostream_iterator<A>(std::cout));

    return 0;
}