Форум » C/C++ для начинающих (C/C++ for beginners) » Read record and enrollStudent() » Ответить

Read record and enrollStudent()

Felicia123: my currently course.h [pre2]#include <iostream> #include <string> #include <conio.h> #include <fstream> using namespace std; class Course{ private: string courseCode; string courseName; int credit; int numOfStudent; public: struct Student{ string studentID; string studentName; double studentMarks; }theStudent[30]; Course(); void setCourseCode( string ); string getCourseCode(); void setCourseName( string ); string getCourseName(); void setCredit( int ); int getCredit(); void setNumOfStudent( int ); int getNumOfStudent(); void setStudentID( string ); string getStudentID(); void setStudentMarks( double ); double getStudentMarks(); void readRecord( ifstream & , int & , Course * ); void enrollStudent( int & , Course * ); void RemoveStudent( int & ); void ModifyCourse( int & ); void GradeList( int & ); void writeRecord( int & ); };[/pre2] and my currentlyreadRecord() & enrollStudent [pre2]void Course :: readRecord( ifstream &inFile , int &sizeCourse , Course *theCourse ){ string SubjectCode; string SubjectName; string StudentName; int theCredit = 0; int sizeOfStudent = 0; string filename; if ( inFile.is_open() ){ inFile.ignore(); for( int i = 0 ; i < sizeCourse ; i++ ){ getline( inFile , SubjectCode ); theCourse.setCourseCode( SubjectCode ); getline( inFile , SubjectName ); theCourse.setCourseName( SubjectName ); inFile >> theCredit; theCourse.setCredit( theCredit); inFile >> sizeOfStudent; theCourse.setNumOfStudent( sizeOfStudent ); inFile.ignore(); for ( int z = 0 ; z < sizeOfStudent ; z++ ){ getline( inFile , theCourse.theStudent[z].studentName); inFile >> theCourse.theStudent[z].studentMarks; inFile.ignore(); } } } cout << sizeCourse << endl; for( int i = 0 ; i < sizeCourse ; i++ ){ cout << theCourse.getCourseCode() << endl << theCourse.getCourseName() << endl << theCourse.getCredit() << endl << theCourse.getNumOfStudent() << endl; for( int z = 0 ; z < theCourse.getNumOfStudent() ; z++ ){ cout << theCourse.theStudent[z].studentName << endl << theCourse.theStudent[z].studentMarks<< endl; } } } void Course :: enrollStudent( int& numOfCourse , Course *theCourse ){ bool found = 0; int foundIndex = 0 ; int choice = 0; cout << "0.Exit " << endl; for( int i = 0 ; i < numOfCourse ; i++ ){ cout << (i+1) << "." << theCourse.courseCode << " " << theCourse.courseName << endl; } cout << "Enter Your Choice : "; cin >> choice; if( choice > 0 && choice < numOfCourse ) theCourse[choice - 1].enrollStudent( numOfCourse , theCourse ); else if(choice != 0) cout << "Invalid Input ! " << endl; cin.ignore(); do{ cout << "Enter student name : "; getline( cin,theStudent[numOfStudent].studentName ); cout << "Enter student's mark : "; double studentMarks; cin >> theStudent[numOfStudent].studentMarks; numOfStudent++; if( numOfStudent > 30 ) cout << " The number of student enrolled for this course are full ! " << endl;//Display error message if maximum student reached }while( numOfStudent < 31 );//Do checking on the number of student that enroll for the course }[/pre2] my main.cpp [pre2]#include "course.h" int main(){ string filename; Course *theCourse; int numOfCourse = 0; int choice = 0; ifstream inFile; cout << "Enter filename to read : "; getline( cin , filename ); cout << endl; inFile.open( filename.c_str() ); if( inFile.fail() ) cout << "Unable to open file !" << endl; inFile >> numOfCourse; theCourse = new Course[numOfCourse];//dynamic array created theCourse->readRecord( inFile, numOfCourse , theCourse ); getch(); system( "cls" ); start: cout << "\tEnrollment System College Penang" << endl << "-----------------------------------------------------" << endl << endl << "1. Enroll a new student into a course" << endl << "2. Remove a student from a course " << endl << "3. Modify a course detail" << endl << "4. Generate grade list" << endl << "5. Save to file " << endl << endl << "Enter Choice : "; cin >> choice; switch( choice ){ case 1: theCourse->enrollStudent( numOfCourse , theCourse ); getch(); break; default: cout << "Invalid Input ! Please re-enter ! " << endl; getch(); system( "cls" ); goto start; } system( "pause" ); return 0; }[/pre2]now my question is , if student keep press the choice 1 , the function of enrollStudent()will keep recall back so am i wrong?

Ответов - 7 новых

Сыроежка: I have not understood the question but let start from considering function readRecord [pre2]void Course :: readRecord( ifstream &inFile , int &sizeCourse , Course *theCourse ){ string SubjectCode; string SubjectName; string StudentName; int theCredit = 0; int sizeOfStudent = 0; string filename; if ( inFile.is_open() ){ inFile.ignore(); for( int i = 0 ; i < sizeCourse ; i++ ){ getline( inFile , SubjectCode ); theCourse.setCourseCode( SubjectCode ); getline( inFile , SubjectName ); theCourse.setCourseName( SubjectName ); inFile >> theCredit; theCourse.setCredit( theCredit); inFile >> sizeOfStudent; theCourse.setNumOfStudent( sizeOfStudent ); inFile.ignore(); for ( int z = 0 ; z < sizeOfStudent ; z++ ){ getline( inFile , theCourse.theStudent[z].studentName); inFile >> theCourse.theStudent[z].studentMarks; inFile.ignore(); } } } cout << sizeCourse << endl; for( int i = 0 ; i < sizeCourse ; i++ ){ cout << theCourse.getCourseCode() << endl << theCourse.getCourseName() << endl << theCourse.getCredit() << endl << theCourse.getNumOfStudent() << endl; for( int z = 0 ; z < theCourse.getNumOfStudent() ; z++ ){ cout << theCourse.theStudent[z].studentName << endl << theCourse.theStudent[z].studentMarks<< endl; } } } [/pre2] This function is a non-static function of the class. So it has the first implicit parameter of type Course * that is denoted as this. In fact your function is decalred as void Course :: readRecord( Course *this, ifstream &inFile , int &sizeCourse , Course *theCourse ); However you do not use this. So maybe it would be better do declare the function as static? But the better approach is to remove the last parameter. Take into account that the code shall not be compiled because you use incorrect syntax to access members of the class through pointer. For example instead of theCourse.setCourseCode( SubjectCode ); shall be theCourse->setCourseCode( SubjectCode ); So my suggesting is to rewrite the function such a way that it would have only one parameter: reference to an input stream. Also I have not understood why did you declare the second parameter of the function and moreover declared as reference though inside the function body I do not see where sizeCourse can be modified.

Felicia123: that's why , the senior also told me that i should use only reference to an input stream . but i don't know how to access to the Course if without using the pointer. can provide some example for my code with using only 1 parameter? i thinking quite long but not sure how to access to the Course.. since my readRecord() is a member of the class Course already..

Сыроежка: I think you should start from defining correctly the class. For example consider the following methods [pre2] void setNumOfStudent( int ); int getNumOfStudent(); void setStudentID( string ); string getStudentID(); void setStudentMarks( double ); double getStudentMarks(); [/pre2] What does mean method setNumOfStudent? I think that number of stuidents depends on how many student were enrolled in a Course. So it shall not be. a public method. Instead there shall be a public method that reports how many students are rolled. Also if you have a fixed size array for enrolled students then I think there shall be a method that returns the maximum number of students that can be enrolled in a Course. Another problem. How to determine for which student are the following methods getNumOfStudent setStudentID applied? Either an index in the array should be used or a student should be searched by name.


Felicia123: ya . for my device program. only maximum 30 student can be enroll in a course . now my problem is . i don't know how to program tha readRecord() by using the method. because my Course got an array which is read the sizeCourse at start and create the dynamic array . and each Course inside have the own function . get what I mean ? sorry for my poor explanation . but i thought i already using the accessor and mutator? so i can straight use if my function like this? [pre2]void readRecord(){ Course->setNumOfStudent( numOfStudent ); Course->setStudentID( studentID ); } [/pre2] like this?

Сыроежка: In my opinion a more correct design will be the following. The definition of structure Student should be public while the pointer to dynamically allocated array of Students should be private. Also I think that member studentMarks should be renamed as studentMark because only one mark is stored. Structure Student should have its own methiod for reading a record. And while was studentMarks defined as double instead of int? Here is a possible design [pre2] struct Student { public: string getName() const { return ( studentName ); } double getMark() const { return ( studentMark ); } istream & readStudent( istream &is ); ostream & saveStudent( ostream &os ) const; private: string studentID; string studentName; double studentMark; }; ostream & Student::saveStudent( ostream &os ) const { return ( os << studentID << ' ' << studentName << ' ' << studentMark << '\n' ); } istream & Student::readStudent( istream &is ) { string record; getline( is, record ); istringstream ss( record ); ss >> studentID >> studentName >> studentMark; return ( is ); } [/pre2] So my suggestion is following. At first remove class Course and test all operations with Student especially reading and writing an object of the class into and from a stream. After all operations with Student will be tested include structure Student into class Course. For example [pre2] #include <iostream> #include <fstream> #include <sstream> using namespace std; struct Student { public: string getName() const { return ( studentName ); } double getMark() const { return ( studentMark ); } istream & readStudent( istream &is ); ostream & saveStudent( ostream &os ) const; private: string studentID; string studentName; double studentMark; }; ostream & Student::saveStudent( ostream &os ) const { return ( os << studentID << ' ' << studentName << ' ' << studentMark << '\n' ); } istream & Student::readStudent( istream &is ) { string record; getline( is, record ); istringstream ss( record ); ss >> studentID >> studentName >> studentMark; return ( is ); } int main() { Student students[10]; // some test code for reading and writing elements of the array using file stream and standard stream cin and cout }[/pre2] The code I typed can contain a typo. It is you who should write the code correctly.

Felicia123: i not really get why i should have ifstream and ofstream for the structure student? because in my option 5 . i will be save the file in txt file . i thought it's just simple ofstream outFile something like this? and beside this . i still having problem for the readRecord() since you said i need only pass throught 1 parameter ? and it's in member of class Course?

Сыроежка: Structure Student should have its own methods of saving and restoring from a file. In this case it will be easy to write general methods of saving and restoring an object of class Course. You will delegate saving and restoring of an object of type Student to it itself. You should design a format of storing one object of Student. For example I would suggest to store one Student in a line separating its members by semicolon. So each record of a file will contain information about one Student. The corresponding methods could look the following way [pre2] ostream & Student::saveStudent( ostream &os ) const { return ( os << studentID << ';' << studentName << ';' << studentMark << '\n' ); } istream & Student::readStudent( istream &is ) { string record; getline( is, record ); istringstream ss( record ); getline( ss, studentID, ';' ); getline( ss, studentName, ';' ); ss >> studentMark; return ( is ); } [/pre2] It is better to use a delimiter as for example a semicolon because member studentName may consist of two or more words. These were methods of structure Student. Class Course will have its own methods for saving and restoring records. But when it will need to store students of the course it delegates the task to each element of dynamically allocated array od Students. As I wrote above try to test the modified structure Student. And if tests will be successfully passed the structure will be incorporated into class Course. It is a good idea to design elements of a compound class separately. After you will be sure that Student can be written and restored from a file then you will incorporate it into Course. Course will have a dynamically allocated array of Student. You can use the same design of storing an object of type Course as for Student that is to save its members separated by a semicolon in a line. So a record of stored object of type Cource will look as courseCode;courseName;credit;numOfStudent\n If the field numOfStudent of the record is not equal to zero then you in a loop will call method readStudent for each element of the dynamically allocated array. So the design of the method for restoring information about a course will look the following way [pre2] std::istream & readInfo( std::istream &is ) // I prefer to name the method as readInfo. You may use any other name { // Here is the stuff for reading one record describing the course in whole. if ( numOfStudent != 0 ) { theStudents = new Student[numOfStudent]; for ( int i = 0; i < numOfStudent; i++ ) theStudents.readStudent( is ); } return ( is ); }[/pre2] After the structure Student will have been tested you can switch to design methods of Course. I think you will need at least two overload subscript operators to access an object of type Student to remoce it or modify according to your menu.



полная версия страницы