我有三个不同的文本文件,分别来自命令行,分别为 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”,而对于其他两个实例,则相同。是否可以仅通过一个效率循环就所有文件和类进行所有提及的作业?无论哪种情况(无论可能与否),建议的解决方案是什么?
修改 为每个类创建这么多不同名称的变量根本不符合成本效益
答案 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;
}