将派生自抽象基类的对象与基类指针的向量数组中的映射一起存储

发布于 2024-11-03 13:16:32 字数 12079 浏览 1 评论 0原文

我正在编写一个使用 OOP 来存储学生记录的程序。目前我只有两个类,一个用于每个称为“课程”的单独课程模块,另一个(如果算上抽象基类,则为两个)用于从“记录”基础派生的名为“物理”的学位课程类型班级。

我在程序中使用了两张地图。一种用于存储每条记录的各个课程并按课程代码对它们进行排序,另一种用于存储所有记录并按 ID 号对它们进行排序。

我计划让用户输入所有学生信息,包括代码,将其存储在向量中(在代码中名为“prec”),然后将向量元素推入用于存储所有记录的映射中。代码还远没有完成,我只是试图运行它来看看我是否走在正确的轨道上。

代码构建时没有任何错误,但是当我尝试运行它时,它会出现错误消息:“调试断言失败:表达式向量下标超出范围”。我觉得这可能与我使用单独的向量元素调用我的函数以在地图中存储课程的方式有关,但我不太明白,任何帮助将不胜感激!

这是我的文件:

头文件:

#ifndef MY_CLASS_H // Pre-processor directives to prevent multiple definition 
#define MY_CLASS_h

#include <iostream>
#include <string>
#include <utility>
#include <map>
#include <fstream>




using std::string;
using std::ostream;
using std::map;
using std::cout;
using std::endl;
using std::cin;

namespace student_record // Defines the namespace student_record in which the classes are defined 
{
    class Course {  /* Create class Course for individual courses, is this better than incorporating
                    all the data separately into the Record class below? Class contains course name, mark achieved and mark weight and course ID */
    protected:
        string course_name;
        double course_mark; 
        int course_Id;

    public:
        Course() {course_name= "Null"; // Default constructor for null course
                  course_mark=0;
                  }

        Course(string course_namein, double course_markin, int course_Idin) {course_name=course_namein; // Parametrized constructor to create course with set name, mark, weight and course ID
                                                                                                   course_mark=course_markin;

                                                                                                   course_Id=course_Idin;}

        ~Course() {course_name.erase(0,course_name.size());}    // Destructor to delete the course name 

        // Access functions to get name, mark and weight //

        double getmark() const {return course_mark;}
        string getname() const {return course_name;}
        int getid() const {return course_Id;}

        friend ostream & operator << (ostream &os, const Course &c);        // Friend function to overload the insertion operator for courses 
    };

    class Record 
    {   // Create class Record as abstract base class for all inherited degree classes

    protected: 
        string student_name;
        int studentid;
        int years;

    public:
        Record() {student_name="Casper";
                  studentid=0;
                  years=0;}     // Default constructor for class Record, produces empty record

        Record(string name, int number, int time) {student_name=name;
                                                   studentid=number;
                                                   years=time;}  // Parametrized constructor for class Record 

        ~Record() {student_name.erase(0, student_name.size());} // Destructor to delete the student name



        virtual int getid()const=0;
        virtual int getyears()const=0;
        virtual void show_record()const=0;
        virtual void print_record(string *filename)const=0;
        virtual void degree_class()const=0;
        virtual void insert_class()=0;


        /* Virtual functions defined to be used in the derived classes (subjects ie, Physics, stamp collecting, etc...) 
        Thus the base class Record is abstract*/
    };


    class Physics: public Record
    {
    private:
        string degree_name;
        typedef map <int, Course> course_map;
        course_map modules;


        void searchdatabase (course_map &courses, int coursecode)const; // Uses iterator to search map for corresponding course to inputted key ( remember to move to function definitions)

        string get_name (const int i, course_map &temp) const{ return temp[i].getname();}
        double get_mark(const int i, course_map &temp)const{ return temp[i].getmark();} // Functions to return the mark, weight and name of a given course corresponding to inputed course code
        int getid()const{return studentid;}
        int getyears()const{return years;}
        void show_record()const;

        void print_record( string *filename) const;
        void degree_class()const;
        void insert_class();
        // Function to insert record into map


    public:
        Physics():Record(){degree_name= "Physics ";}
        Physics(string name,int Id, int time):Record( name,  Id,  time){degree_name= "Physics";}
        ~Physics() {degree_name.erase(0, degree_name.size());}


    };
}


#endif

函数定义:

#include <iostream>
#include <string>
#include <utility>
#include <map>
#include <fstream>
#include <vector>
#include "Database_header.h"

using namespace std;
using namespace student_record;

ostream & student_record::operator<< (ostream &os, const Course &c)
{
    os<< "Course code" << c.course_Id << " \n Course name: " <<c.course_name << " \n Mark " << c.course_mark <<endl;
    return os;
}

// Function to insert classes //
void Physics::insert_class()
{

    int courseid;
    string coursename;
    double mark;
    cout << " Enter course code " << endl;
    cin >> courseid;
    cout << " \n Enter course name " << endl;
    cin >> coursename;
    cout << " \n Enter mark achieved " << endl;
    cin >> mark;

    Course temp (coursename, mark, courseid);

    modules.insert(pair<int, Course>(courseid, temp));

}

void Physics::searchdatabase(course_map &courses, int coursecode) const // Function to search for specific course mark based on course code, need to modify this!!!!
                                                                        //takes in a map as its argument, although i suppose can use student.modules? 

        {
            course_map::iterator coursesIter;
            coursesIter=courses.find(coursecode);
            if(coursesIter != courses.end())
            {
                cout << " Course Code " << 
                coursecode << " corresponds to " <<
                coursesIter ->second << endl;
            }
            else { cout << " Sorry, course not found " << endl; }
        }

void Physics::print_record( string *filename) const // Function for printing record to the file
{
    ofstream myoutputfile;
    myoutputfile.open(*filename,ios::app);
    if(!myoutputfile.good())
        {
        // Print error message and exit
        cerr<<"Error: file could not be opened"<<endl;
        }

    if(myoutputfile.good())
    {
    myoutputfile << "Student name: " << student_name << endl
                 << "\n Student ID: "  << studentid << endl
                 << "\n Year: " << years << endl;
                  course_map::iterator modulesiter; // Iterator to print out courses using overloaded << function (I think?)
    for(modulesiter==modules.begin();modulesiter!=modules.end();modulesiter++)
        {
            myoutputfile<<modulesiter->second << endl;
        }
    }


}

void Physics::show_record() const // Function for showing specific student record on screen ( with iterator for map of courses)
{
    cout << "Student name: " << student_name;
    cout << "\n Student ID: " << studentid;
    cout << "\n Years on course: " << years;
    cout << "\n Courses and grades: ";
    course_map::iterator modulesiter; // Iterator to print out courses using overloaded << function (I think?)
    for(modulesiter==modules.begin();modulesiter!=modules.end();modulesiter++)
        {
            cout<<modulesiter->second << endl;
        }

}

void Physics::degree_class()const
{
    double temp;
    vector<double> dynarr; // Create a vector array to store the grades extracted from the course map for each student
    course_map::iterator modulesiter; 
    for(modulesiter==modules.begin();modulesiter!=modules.end();modulesiter++) // Iterate through map and push values into each vector
        {
            Course ghost;
            ghost=modulesiter->second;
            dynarr.push_back(ghost.getmark());
        }
    double sum(0);
    for(int i(0);i<=dynarr.size();i++)
    {
        sum+=dynarr[i];
    }

    temp=sum/dynarr.size();

    if( temp>=40 && temp <=49.9)
    {
        cout << "The student has achieved a 3rd class degree with an average of: \n "
             << temp;
    }

    else if( temp>=50 && temp <=59.9)
    {
        cout << "The student has achieved a 2:2 degree with an average of: \n "
             << temp;
    }

    else if( temp>=60 && temp <=69.9)
    {
        cout << "The student has achieved a 2:1 degree with an average of: \n "
             << temp;
    }

    else if( temp>=70)
    {
        cout << "The student has achieved a 1st class degree with an average of: \n "
             << temp;
    }

    else { cout << "The student has failed the degree " << endl;}


}

和主 cpp 文件:

#include <iostream>
#include <utility>
#include <map>
#include <iomanip>
#include <vector>
#include "Database_header.h"
#include <fstream>

using namespace std;
using namespace student_record;

void main()
{
    // Create map to store students with ID keys //

    string full_name;
    int id;
    int time;
    string degree_name;

    vector<Record*> prec;
    // Vector of base class pointers to store all the different records first. No need to specify length as it is a vector! (Advantage over dynamic array?)
    char student_test('y'); // Condition for adding students to the record //
    int q(0);
    while (student_test=='y' || student_test=='Y')
    {
         // Counter for while loop


        cout<< " \n Please enter the student name " << endl;
        getline(cin, full_name);

        // Enter student name, check it is a string? //

        cout<< "\n Please enter student ID " << endl;
        cin >> id;

        // Check if not integer or number, if not need error message //

        cout << "\n Please enter the number of years on the course " << endl;
        cin >> time;

        // Check if not integer or number, if not need error message //

        cout<< "\n Please enter degree type " << endl;
        cin>>degree_name;

        if(degree_name=="Physics" || degree_name=="physics")    // create object of appropriate derived class ( Physics, Chem, Maths, Bio)
        {
            prec.push_back(new Physics(full_name, id, time));
        }

        char class_test('y'); // test condition for class insertion loop

        while(class_test=='y') // Add courses+marks into course map
        {
            cout << " \n Add classes to student record " << endl;
            prec[q]->insert_class();
            cout << " \n Add another class? Y/N" << endl;
            cin>>class_test;
        }

        cout << "Enter another student? Y/N " << endl;
        cin >> student_test;

        if(student_test=='N' && student_test=='n')
        {
            cout << "\n Thank you for using the student database, Goodbye !" << endl;
        }

        q++; // increment counter, to keep track of of vectors of base class pointers, and also be able to output number of students

    }

    // Next insert all records into map //
    typedef map<int, Record*> studentlist;
    studentlist studentmap;

    for(int i(0); i<=prec.size(); i++)
    {
        studentmap.insert(pair<int, Record*> (prec[i]->getid(), prec[i]));
    }

}

非常感谢!

I'm writing a program that uses OOP to store student records. At the moment I only have two classes, one for each individual course module called 'Courses', and one ( well two if you count the abstract base class) for the type of degree programme called 'Physics' derived from the 'Records' base class.

I'm using two maps in the program. One to store the individual courses for each individual record and sort them by course code, and one to store all the records and sort them by ID numbers.

I planned on having the user input all student information, including codes, storing this in a vector (named 'prec' in the code), then pushing the vector elements into the map used to store all the records. The code is far from finished, I was just attempting to run it to see if I was on the right track.

The code builds without any errors, but when I attempt to run it, it comes up with the error message: " Debug assertion failed: expression vector subscript out of range". I feel this may have something to do with the way I am using individual vector elements to call my functions to store courses in the maps but I cant quite get it, any help would be much appreciated!

Here are my files:

header file:

#ifndef MY_CLASS_H // Pre-processor directives to prevent multiple definition 
#define MY_CLASS_h

#include <iostream>
#include <string>
#include <utility>
#include <map>
#include <fstream>




using std::string;
using std::ostream;
using std::map;
using std::cout;
using std::endl;
using std::cin;

namespace student_record // Defines the namespace student_record in which the classes are defined 
{
    class Course {  /* Create class Course for individual courses, is this better than incorporating
                    all the data separately into the Record class below? Class contains course name, mark achieved and mark weight and course ID */
    protected:
        string course_name;
        double course_mark; 
        int course_Id;

    public:
        Course() {course_name= "Null"; // Default constructor for null course
                  course_mark=0;
                  }

        Course(string course_namein, double course_markin, int course_Idin) {course_name=course_namein; // Parametrized constructor to create course with set name, mark, weight and course ID
                                                                                                   course_mark=course_markin;

                                                                                                   course_Id=course_Idin;}

        ~Course() {course_name.erase(0,course_name.size());}    // Destructor to delete the course name 

        // Access functions to get name, mark and weight //

        double getmark() const {return course_mark;}
        string getname() const {return course_name;}
        int getid() const {return course_Id;}

        friend ostream & operator << (ostream &os, const Course &c);        // Friend function to overload the insertion operator for courses 
    };

    class Record 
    {   // Create class Record as abstract base class for all inherited degree classes

    protected: 
        string student_name;
        int studentid;
        int years;

    public:
        Record() {student_name="Casper";
                  studentid=0;
                  years=0;}     // Default constructor for class Record, produces empty record

        Record(string name, int number, int time) {student_name=name;
                                                   studentid=number;
                                                   years=time;}  // Parametrized constructor for class Record 

        ~Record() {student_name.erase(0, student_name.size());} // Destructor to delete the student name



        virtual int getid()const=0;
        virtual int getyears()const=0;
        virtual void show_record()const=0;
        virtual void print_record(string *filename)const=0;
        virtual void degree_class()const=0;
        virtual void insert_class()=0;


        /* Virtual functions defined to be used in the derived classes (subjects ie, Physics, stamp collecting, etc...) 
        Thus the base class Record is abstract*/
    };


    class Physics: public Record
    {
    private:
        string degree_name;
        typedef map <int, Course> course_map;
        course_map modules;


        void searchdatabase (course_map &courses, int coursecode)const; // Uses iterator to search map for corresponding course to inputted key ( remember to move to function definitions)

        string get_name (const int i, course_map &temp) const{ return temp[i].getname();}
        double get_mark(const int i, course_map &temp)const{ return temp[i].getmark();} // Functions to return the mark, weight and name of a given course corresponding to inputed course code
        int getid()const{return studentid;}
        int getyears()const{return years;}
        void show_record()const;

        void print_record( string *filename) const;
        void degree_class()const;
        void insert_class();
        // Function to insert record into map


    public:
        Physics():Record(){degree_name= "Physics ";}
        Physics(string name,int Id, int time):Record( name,  Id,  time){degree_name= "Physics";}
        ~Physics() {degree_name.erase(0, degree_name.size());}


    };
}


#endif

function definitions:

#include <iostream>
#include <string>
#include <utility>
#include <map>
#include <fstream>
#include <vector>
#include "Database_header.h"

using namespace std;
using namespace student_record;

ostream & student_record::operator<< (ostream &os, const Course &c)
{
    os<< "Course code" << c.course_Id << " \n Course name: " <<c.course_name << " \n Mark " << c.course_mark <<endl;
    return os;
}

// Function to insert classes //
void Physics::insert_class()
{

    int courseid;
    string coursename;
    double mark;
    cout << " Enter course code " << endl;
    cin >> courseid;
    cout << " \n Enter course name " << endl;
    cin >> coursename;
    cout << " \n Enter mark achieved " << endl;
    cin >> mark;

    Course temp (coursename, mark, courseid);

    modules.insert(pair<int, Course>(courseid, temp));

}

void Physics::searchdatabase(course_map &courses, int coursecode) const // Function to search for specific course mark based on course code, need to modify this!!!!
                                                                        //takes in a map as its argument, although i suppose can use student.modules? 

        {
            course_map::iterator coursesIter;
            coursesIter=courses.find(coursecode);
            if(coursesIter != courses.end())
            {
                cout << " Course Code " << 
                coursecode << " corresponds to " <<
                coursesIter ->second << endl;
            }
            else { cout << " Sorry, course not found " << endl; }
        }

void Physics::print_record( string *filename) const // Function for printing record to the file
{
    ofstream myoutputfile;
    myoutputfile.open(*filename,ios::app);
    if(!myoutputfile.good())
        {
        // Print error message and exit
        cerr<<"Error: file could not be opened"<<endl;
        }

    if(myoutputfile.good())
    {
    myoutputfile << "Student name: " << student_name << endl
                 << "\n Student ID: "  << studentid << endl
                 << "\n Year: " << years << endl;
                  course_map::iterator modulesiter; // Iterator to print out courses using overloaded << function (I think?)
    for(modulesiter==modules.begin();modulesiter!=modules.end();modulesiter++)
        {
            myoutputfile<<modulesiter->second << endl;
        }
    }


}

void Physics::show_record() const // Function for showing specific student record on screen ( with iterator for map of courses)
{
    cout << "Student name: " << student_name;
    cout << "\n Student ID: " << studentid;
    cout << "\n Years on course: " << years;
    cout << "\n Courses and grades: ";
    course_map::iterator modulesiter; // Iterator to print out courses using overloaded << function (I think?)
    for(modulesiter==modules.begin();modulesiter!=modules.end();modulesiter++)
        {
            cout<<modulesiter->second << endl;
        }

}

void Physics::degree_class()const
{
    double temp;
    vector<double> dynarr; // Create a vector array to store the grades extracted from the course map for each student
    course_map::iterator modulesiter; 
    for(modulesiter==modules.begin();modulesiter!=modules.end();modulesiter++) // Iterate through map and push values into each vector
        {
            Course ghost;
            ghost=modulesiter->second;
            dynarr.push_back(ghost.getmark());
        }
    double sum(0);
    for(int i(0);i<=dynarr.size();i++)
    {
        sum+=dynarr[i];
    }

    temp=sum/dynarr.size();

    if( temp>=40 && temp <=49.9)
    {
        cout << "The student has achieved a 3rd class degree with an average of: \n "
             << temp;
    }

    else if( temp>=50 && temp <=59.9)
    {
        cout << "The student has achieved a 2:2 degree with an average of: \n "
             << temp;
    }

    else if( temp>=60 && temp <=69.9)
    {
        cout << "The student has achieved a 2:1 degree with an average of: \n "
             << temp;
    }

    else if( temp>=70)
    {
        cout << "The student has achieved a 1st class degree with an average of: \n "
             << temp;
    }

    else { cout << "The student has failed the degree " << endl;}


}

and main cpp file:

#include <iostream>
#include <utility>
#include <map>
#include <iomanip>
#include <vector>
#include "Database_header.h"
#include <fstream>

using namespace std;
using namespace student_record;

void main()
{
    // Create map to store students with ID keys //

    string full_name;
    int id;
    int time;
    string degree_name;

    vector<Record*> prec;
    // Vector of base class pointers to store all the different records first. No need to specify length as it is a vector! (Advantage over dynamic array?)
    char student_test('y'); // Condition for adding students to the record //
    int q(0);
    while (student_test=='y' || student_test=='Y')
    {
         // Counter for while loop


        cout<< " \n Please enter the student name " << endl;
        getline(cin, full_name);

        // Enter student name, check it is a string? //

        cout<< "\n Please enter student ID " << endl;
        cin >> id;

        // Check if not integer or number, if not need error message //

        cout << "\n Please enter the number of years on the course " << endl;
        cin >> time;

        // Check if not integer or number, if not need error message //

        cout<< "\n Please enter degree type " << endl;
        cin>>degree_name;

        if(degree_name=="Physics" || degree_name=="physics")    // create object of appropriate derived class ( Physics, Chem, Maths, Bio)
        {
            prec.push_back(new Physics(full_name, id, time));
        }

        char class_test('y'); // test condition for class insertion loop

        while(class_test=='y') // Add courses+marks into course map
        {
            cout << " \n Add classes to student record " << endl;
            prec[q]->insert_class();
            cout << " \n Add another class? Y/N" << endl;
            cin>>class_test;
        }

        cout << "Enter another student? Y/N " << endl;
        cin >> student_test;

        if(student_test=='N' && student_test=='n')
        {
            cout << "\n Thank you for using the student database, Goodbye !" << endl;
        }

        q++; // increment counter, to keep track of of vectors of base class pointers, and also be able to output number of students

    }

    // Next insert all records into map //
    typedef map<int, Record*> studentlist;
    studentlist studentmap;

    for(int i(0); i<=prec.size(); i++)
    {
        studentmap.insert(pair<int, Record*> (prec[i]->getid(), prec[i]));
    }

}

Thanks so much!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一梦等七年七年为一梦 2024-11-10 13:16:32
for(int i(0); i<=prec.size(); i++)
{
    studentmap.insert(pair<int, Record*> (prec[i]->getid(), prec[i]));
}

应该是我< prec.size() 而不是 <=

for(int i(0); i<=prec.size(); i++)
{
    studentmap.insert(pair<int, Record*> (prec[i]->getid(), prec[i]));
}

Should be i < prec.size() instead of <=

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文