首先,祝遇到我问题的人们新年快乐。
我目前正在学习C ++,并且有一个课堂项目要完成。
简而言之,我的代码(到目前为止)应该实例化具有从txt文件(名称,注册号和的映射)中读取的详细信息的学生对象,并将该学生添加到列表中。 然后,我阅读了第二个txt文件(由注册号,课程代码和标记组成),并检查读取的内容和列表之间是否存在学生注册号的匹配。 如果匹配,我应该将从txt文件中读取的分数插入地图(学生对象的一部分)中,这样以后,每个学生都有一张地图,其中包含所修课程和取得的分数 我似乎可以很好地创建列表,然后使用stringstream读取第二个文件并遍历该列表以比较reg-number。 如果有匹配项,则调用add mark方法将标记添加到地图。 就是这样。如果在我完成地图插入之后,我循环并打印学生的地图,则该地图为空。对于所有学生。为了确认这一点,我使用了map.size()。 我已经尝试了多种方法来理解和纠正此问题,但似乎我漏掉了某些要点。本能告诉我,添加标记方法正在将引用复制到传递的变量中,然后在main方法中由字符串流销毁该引用,因此在映射中未显示任何数据。不幸的是,我不能更改头文件中的任何代码,只能实现声明的内容。 在阅读了std库文档中的字符串,映射等信息,并尝试了多种纠正行为的方法之后,我很茫然。 任何建议将不胜感激,因此我可以继续进行该项目并更好地了解正在发生的事情。我已经在下面添加了文件。还有一个Person基类,但是我没有更改它,因为它仅包含一个setter和getter。 预先非常感谢。学生标题:
#ifndef _STUDENT_H_
#define _STUDENT_H_
#include <string>
#include <map>
#include <stdexcept>
#include "Person.h"
using namespace std;
class NoMarkException: public exception
{
};
class Student: public Person
{ public:
// constructor should initialise name and registration number using arguments
// and initialise marks map to be empty
Student(const string &name, int regNo);
// method to return registration number
int getRegNo() const;
// method to add the mark to the map
// if a mark for the module is already present it should be overwritten
void addMark(const string& module, float mark);
// method to retrieve the mark for a module
// should throw NoMarkException if student has no mark for that module
float getMark(const string &module) const throw (NoMarkException);
private:
int regNo;
map<string, float> marks; // keys are modules, values are marks in range 0.0 to 100.0
// friend function to output details of student to stream
// should output name, regno, and minimum, maximum and average marks on a single line
// if the student has no marks "has no marks" should be output instead of the marks
friend ostream& operator<<(ostream &str, const Student &s);
};
#endif
Student.cpp文件:
#include <iostream>
#include "Student.h"
#include "Person.h"
using namespace std;
//constructor makes a student object and initialises the map; marks.
Student::Student(const string &name, int regNo) : Person(name) {
this->name = name;
this->regNo = regNo;
map<string, float> marks;
}
//implemented from the header file. Returns the registration number.
int Student::getRegNo() const {
return regNo;
}
// implemented as per header file request. adds marks to the map. if a mark exists, then it is overwritten.
void Student::addMark(const string &module, float mark) {
marks[module] = mark;
cout << "added: " << marks[module]<< endl;
}
//used to find marks in a map.
float Student::getMark(const string &module) const throw (NoMarkException) {
auto search = marks.find(module);
//line to test the map size after using addMark.
cout << "size after inputted values: "<< marks.size();
return marks[module];
}
main.cpp文件
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <list>
#include "Student.h"
using namespace std;
//main method to obtain a file name from a user and read the file.
//method passes each .. to student.cpp
int main() {
//setting up variables required
string fileName;
const string fileEnd = ".txt";
string line;
string line2;
ifstream file;
int reg;
int reg2;
string studName;
string lastName;
float mark;
string module;
list<Student> listOfStudents;
cout << "Please enter a file name to access..." << std::endl;
cin >> fileName;
fileName += fileEnd;
// opening file an reading its contents. values are prepared and sent to the Student constructor. Fills a list
// with student objects created with variables read from the studs.txt file.
//checks file is found and exits the program if not
file.open(fileName);
if (!file) {
cerr << "Unable to open file " << fileName << endl;
exit(1);
}
while (getline (file, line)) {
stringstream stream (line);
stream >> reg >> studName >> lastName;
studName += (' ' + lastName);
cout << "Student: " << studName << " has been created." << endl;
listOfStudents.push_front(Student(studName, reg));
}
file.close();
cout << "The list of students has been created :)" << endl << endl;
cout << "Please enter the name of the next file to open"<< endl;
cout << listOfStudents.size()<<endl;
// opening second file. If file not found, exit with an error code.
// otherwise read each line, separate the three words into variables, then loop through the previously created list
//and look for a match of regNo. if true then call the addMark method to add the module and mark to the student's map.
cin >> fileName;
fileName += fileEnd;
file.open(fileName);
if (!file) {
cerr << "Unable to open file " << fileName << endl;
exit(1);
}
while(getline(file, line))
{
istringstream line_stream(line);
line_stream >> reg2 >> module >> mark;
for(Student stud : listOfStudents){
if(stud.getRegNo() == reg2){//out << "Match reg2: " << reg2 << " with stud: " << stud.getName() <<stud.getRegNo()<< endl;
stud.addMark(module,mark); }
}
}
//testing the get mark method of student class. with a module that is in the map. expecting a result
for(Student s :listOfStudents){
cout << s.getMark("CE151") << endl;
}
return 0;
}
答案 0 :(得分:6)
每次要添加Mark时,您都会创建一个Student的临时副本,然后将其丢弃。您无需复制它,而是使用引用,如下所示:
for (auto& stud: listOfStudents) /* stud.addMark */
打印结果时避免复制学生也是一个好主意:
for (const auto& stud: listOfStudents) /* stud.getMark */
Aaa和另外一件事:
float getMark(const string &module) const throw (NoMarkException);
动态异常规范在C ++ 11中已弃用,在更高版本的标准中已删除。认为这是一种不好的做法,应该避免。
答案 1 :(得分:1)
用户的答案:grungegurunge
几乎就是您要寻找的答案。但是,看完你的课后。我注意到在私有部分的成员变量中,您已经声明了map<string, float> marks
,这是可以的。但是,当我在设置name
和regNo
之后查看您的类的构造函数时,您似乎在声明另一个名为map<string, float>
的{{1}},其中该变量仅在构造函数本地什么也没做。您在具有自动存储功能的堆栈上创建本地内存,从不使用它,然后在对象超出范围后被销毁;不必在这里声明它。
marks