Vector data is lost after it goes out of scope - c++

I'm working on a project where I use a forward list and vector together and output their values. The forward list is a list of Frame objects, and the vector is a vector of Display objects. The issue is that after the creation of the objects in InsertFrame(), the values of the vector are lost and essentially become garbage. I can see in the debugger it happens right after the function ends, which leads me to believe it has to do with the variables going out of scope. Here is the main creation class
// Animation.cpp
#include <crtdbg.h>
#include <iostream>
#include <string>
#include <vector>
#include <forward_list>
using namespace std;
#include "Display.h"
#include "Frame.h"
#include "Animation.h"
#include "GPUMemoryDisplay.h"
#include "SystemMemoryDisplay.h"
void Animation::InsertFrame() {
int numDisplays; //for user input of display number
vector <Display*>v; //vector for containing display objects
int p_x; //will contain user input for pixel_x
int p_y; //will contain user input for pixel_y
int p_duration; //will contain user input for duration
int p_type ; //will contain display type as int value
char * p_name; //temp string to contain user input for name
string d_name; //will contain p_name to be passed to display constructor
string frameName; //contains user input for the frame name
string gpu_shader; //contains gpu name if gpu type is selected
int q = 0; //used to count the diplay #
//begin reading user input
cout << "Insert a Frame in the Animation\nPlease enter the Frame filename: ";
cin >> frameName;
cout << "Entering the Frame Displays (the sets of dimensions and durations) " << endl;
cout << "Please enter the number of Displays: ";
cin >> numDisplays;
//display creation loop for # of displays entered
while (numDisplays > 0) {
cout << "Please enter pixel x-width for Display #" << q << " pixel_x:";
cin >> p_x;
cout << "Please enter pixel y-width for Display #" << q << " pixel_y:";
cin >> p_y;
cout << "Please enter the duration for this Display: ";
cin >> p_duration;
cout << "Please enter the name for this Display: ";
cin >> d_name;
cout << "Please enter the type for this display (1 = SystemMemoryDisplay, 2 = GPUMemoryDisplay): ";
cin >> p_type;
p_name = new char[d_name.length() + 1]; //allocate for the size of the name entered
strcpy(p_name, d_name.c_str()); //copy string to char []
if (p_type == 2) {
//input for GPU shader
cout << "Please enter the file name of the associated GPU Shader: ";
cin >> gpu_shader;
Display *gpu_p = new GPUMemoryDisplay(p_x, p_y, p_duration, p_name, gpu_shader);
v.push_back(static_cast <Display*>(gpu_p)); //casting to a display* and pushing onto the vector
numDisplays--;
q++;
}
else {
Display *sm_p = new SystemMemoryDisplay(p_x, p_y, p_duration, p_name);
v.push_back(static_cast <Display*>(sm_p));//casting to a display* and pushing onto the vector
numDisplays--;
q++;
}
cout << "\n";
}
Frame t_frame = Frame(frameName, v); //new frame holds vector which contains displays
//check if forward list is empty
if (frames.empty()) {
cout << "\nThis is the first Frame in the list \n\n";
frames.push_front(t_frame);
}
else {
forward_list <Frame>::iterator it;
int x = 0; // used for size of current forward_list
//iterate forward list to obtain the size
for (it = frames.begin(); it != frames.end(); ++it) {
x++;
}
if (x == 1) {
it = frames.begin();
frames.insert_after(it, t_frame);
}
else {
cout << "There are " << x << " Frame(s) in the list\n" << "Please specify the position, between 0 and " << x << " to insert after : ";
cin >> x; //read in where user wants to put the frame
//iterate to desired position and insert
forward_list <Frame>::iterator it;
it = frames.begin();
while (x != 0 && it != frames.end()) {
it++;
x--;
}
frames.insert_after(it, t_frame);
}
}
}
And the header/cpp files for Frame and Display
// Frame.h
#pragma once
class Frame
{
string fileName;
vector<Display*> displays;
public:
Frame(string s, vector<Display*> d) :fileName(s), displays(d) {}
Frame(const Frame&);
~Frame()
{
vector<Display*>::iterator it;
for (it = displays.begin(); it != displays.end(); it++)
delete *it;
}
friend ostream& operator<<(ostream&, Frame&);
};
#pragma once
// Display.h
class Display
{
protected: // accessible to derived classes
int pixel_x;
int pixel_y;
int duration;
char* name;
public:
Display(int x, int y, int duration, char* name);
Display(const Display&);
virtual ~Display() //makes class abstract, cannot be instantiated, most general class
{
if (name)
delete[]name;
}
virtual int BufferSize() = 0; // overridden function Polymorphic function
friend ostream& operator<<(ostream&, Display&);
};
// Display.cpp
#include <crtdbg.h>
#include <iostream>
#include <string>
#include <vector>
#include <forward_list>
using namespace std;
#include "Display.h"
#include "GPUMemoryDisplay.h"
Display::Display(int x, int y, int d, char* n) :pixel_x(x), pixel_y(y), duration(d), name(n) {
}
Display::Display(const Display& p) {
//copy values from p
pixel_x = p.pixel_x;
pixel_y = p.pixel_y;
duration = p.duration;
size_t len = strlen(p.name);
name = new char[len + 1];
strcpy(name, p.name);
//cout << pixel_x << pixel_y << duration << name;
}
I have two sub classes of Display called GPUMemoryDisplay and SystemMemoryDisplay, however I believe that part of the code is fine as I can see their values stored correctly in the debugger. Included below just in case.
#pragma once
// SystemMemoryDisplay.h
class SystemMemoryDisplay : public Display
{
public:
SystemMemoryDisplay(int x, int y, int duration, char* name) :Display(x, y, duration, name) {};
SystemMemoryDisplay(const SystemMemoryDisplay& RGMD) :Display(RGMD) {}
int BufferSize() { return pixel_x*pixel_y * sizeof(double); }
};
#pragma once
//GPUMemoryDisplay.h
//this is the derived class of display
class GPUMemoryDisplay : public Display
{
string shader;
public:
GPUMemoryDisplay(int x, int y, int duration, char* name, string shader) :Display(x, y, duration, name), shader(shader) {};
GPUMemoryDisplay(const GPUMemoryDisplay& RGPUMD) :shader(RGPUMD.shader), Display(RGPUMD) {}
string GetShader() { return shader; }
int BufferSize() { return pixel_x*pixel_y * sizeof(float); } //this is the overridden function from Display class
};
In summary I have a forward list of frames, each frame can contain a vector of Display objects. However when the InsertFrame() function exits, the display data is lost.

Once your stack-allocated Frame t_frame = Frame(frameName, v); objects go out of scope their destructors are called and will delete all the objects pointed by pointers stored in Frame::displays. You need to implement appropriate copy and / or move constructor and assignment operators that will transfer those pointers correctly. You should use ::std::unique_ptr to keep ownership of allocated objects instead of using raw pointers and deleting them manually and ::std::string to mange strings instead of raw pointer to char. Also putting using namespace std; in-between includes is also no good, if you are going to use it at least place it after includes.

Related

Why isn't my class using the values I've given it?

In the process of trying to understand and use classes and methods, I have been trying to create a class with private values that uses a method to alter those values. I create a program that requests input from a user (a length and width) and creates a "rectangle" from those values (it just stores the values they input as if it was a rectangle.) For some reason, the method I used doesn't alter the private length and width values in the class. I used the .h file to create the class and the .cpp to create the function that gets input with the main.cpp being used to call the function. For the sake of simplicity, I removed the input validation section of the code in the .cpp file because it does not affect the class values. Can you help me find my mistake?
My .h file with the class in it:
#pragma once
#include <iostream>
using namespace std;
class Rectangle
{
private:
double length;
double width;
public:
Rectangle()
{
length = 0;
width = 0;
}
Rectangle(double a)
{
length = a;
width = a;
}
Rectangle(double l, double w)
{
length = l;
width = w;
}
void SetLenWid(double l, double w)
{
if (l == w)
{
Rectangle (l);
cout << "You have created a square with sides equal to " << length << endl;
}
else
{
Rectangle (l, w);
cout << "You have created a rectangle of length = " << length << " and width = " << width << endl;
}
}
};
The Rectangle.cpp file:
#include "Rectangle.h"
#include <iostream>
void getInput()
{
double l, w;
cout << "Enter the length: ";
cin >> l;
cout << "Enter the width ";
cin >> w;
Rectangle init;
init.SetLenWid(l, w);
}
Finally, my main.cpp:
#include "Rectangle.h"
#include "Rectangle.cpp"
#include <iostream>
using namespace std;
int main()
{
getInput();
return 0;
}
Sorry for the very long-winded question!
Rectangle(l, w); doesn't do what you think it does. It creates a temporary rectangle, which is then destroyed immedately.
Rectangle(l); also doesn't do what you expect. It's equivalent to Rectangle l;, which creates a rectangle named l using the 0-argument constructor.
You want *this = Rectangle(l, w);, or just assign to the fields directly.

accessing an array through pointer

I wanted to create a database like class through OOP. In this class, there are 3 arrays which act as columns in a table.I insert data through insert() function and prints data through printEntries() function. But that function can't access the arrays to retrieve data.
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
using namespace std;
class subject{
public:
int numOfStudents;
string subjectId;
int * marksArray;
int * indexArray;
char * gradeArray;
int index ; // index for inserting data
subject(int students , string subjectName){
numOfStudents = students;
subjectId = subjectName;
this->index =0 ;
//creating and pointing to arrays
int A[numOfStudents]; marksArray = A;
int B[numOfStudents]; indexArray = B;
char C[numOfStudents]; gradeArray = C;
}
void insert(int studentId , int mark , char grade){
indexArray[index] = studentId;
marksArray[index] = mark;
gradeArray[index] = grade;
this->index = this->index +1;
}
int getNumberOfEntries(){
return index ;
}
void printEntries(){
cout<< indexArray[0] << " O" << marksArray[0] << " " << gradeArray[0] << endl;
cout<< indexArray[1] << " OOO" << marksArray[1] << " " << gradeArray[1] << endl;
cout<< indexArray[2] << " OO" << marksArray[2] << " " << gradeArray[2] << endl;
}
};
int main(int argc, char const *argv[]){
subject S(10,"Mathematics");
cout<<S.subjectId<<endl;
cout<<S.numOfStudents<<endl;
S.insert(35,34,'A');
S.insert(33,34,'B');
S.insert(54,34,'C');
S.insert(21,34,'D');
S.insert(14,34,'F');
S.printEntries();
return 0;
}
output is :
Mathematics
10
35 O34 A
0 OOO0
As pointed out by #paddy in the comments to your question, your issue is within the constructor.
//creating and pointing to arrays
int A[numOfStudents]; marksArray = A;
int B[numOfStudents]; indexArray = B;
char C[numOfStudents]; gradeArray = C;
What you are doing is saving the address of the very first element and the rest disappears after you leave the constructor. you are lucky that it's even allowing you to save the first insert and to quote the comment what you are doing is "defined is undefined behavior"
Replacing the pointers with std::vectors and inserting you elements there will be must easier.
class subject
{
public: // It's considered bad practive to have public data members in a class
std::vector<int> marksVector;
std::vector<int> indexVector;
std::vector<char> gradeVector;
// ...
void insert(int studentId , int mark , char grade){
indexVector.push_back(studentId);
marksVector.push_back(mark);
gradeVector.push_back(grade);
// No longer need to worry about index for next insert
}
};

Why doesn't the stl vector store my class object with the correct values?

I'm using a vector v to store a class object called t_display. I've checked with the debugger and I can see the display object is instantiated correctly. However, when I pass it into the vector with v.push_back() or v.insert(), it stores every value as -842150451. I can see this in the print statements and in the debugger and I cant figure out why it's storing the object this way. Additionally, its storing the integer values this way every time i execute the program, which leads me to believe its not a memory issue although i cant be sure. I've checked all over stack overflow and cppreference. Any advice would be appreciated.
here is the class where I create the object and pass into the vector. I just want the vector to contain the newly made object t_display at the first element.
Animation.cpp
#include <crtdbg.h>
#include <iostream>
#include <string>
#include <vector>
#include <forward_list>
using namespace std;
#include "Display.h"
#include "Animation.h"
void Animation::InsertFrame() {
int numDisplays;
vector <Display>v;
int p_x;
int p_y=0;
int p_duration=0;
string p_name;
string frameName;
cout << "Insert a Frame in the Animation\nPlease enter the Frame filename" << endl;
cin >> frameName;
cout << "Entering the Frame Displays (the sets of dimensions and durations) " << endl;
cout << "Please enter the number of Displays :" << endl;
cin >> numDisplays;
vector <Display>::iterator it;
it = v.begin();
while (numDisplays > 0) {
cout << "Please enter pixel x for Display #0 pixel_x:";
cin >> p_x;
cout << "\nPlease enter pixel y for Display #0 pixel_y:" << endl;
cin >> p_y;
cout << "\nPlease enter the duration sec for this Display :" << endl;
cin >> p_duration;
cout << "\nPlease enter the name for this Display : " << endl;
cin >> p_name;
Display t_display = Display(p_x, p_y, p_duration, (char *)p_name.c_str());
//it = v.insert(it, t_display);
v.push_back(t_display);
numDisplays--;
}
Display.h
// Display.h
#pragma once
class Display
{
int pixel_x;
int pixel_y;
int duration;
char* name;
public:
Display(int x, int y, int duration, char* name);
Display(const Display&);
~Display();
friend ostream& operator<<(ostream&, Display&);
};
## Display.cpp ##
#include <crtdbg.h>
#include <iostream>
#include <string>
#include <vector>
#include <forward_list>
using namespace std;
#include "Display.h"
int q = 0;
Display::Display(int x, int y, int d, char* n):pixel_x(x), pixel_y(y), duration(d), name(n) {}
Display::Display(const Display&) {
}
Display::~Display() {
}
It turns out that I didn't write a copy constructor.

Using a class within a class

I have a very specific question on a program I am writing which makes a battleship game. I have the header file provided to me and I must implement the function definitions within the defined header file. I will post my entire code, however, I am only having trouble implementing the function void ship::printShip() const. I need it to access information for a class within a class and I have a function provided that I am using under location void print() const, however, it wants me to create a pointer in order to access the information under print. I will post the function definitions and the header file along with the error message.
Header file:
#ifndef BATTLESHIP_H_
#define BATTLESHIP_H_
// coordinates (location) of the ship and shots
class location{
public:
location(); // void constructor, assigns -1 to X
void pick(); // picks a random location
void fire(); // asks the user to input coordinates of the next shot
void print() const; // prints location in format "a1"
// returns true if the two locations match
friend bool compare(location, location);
private:
static const int fieldSize = 5; // the field (ocean) is fieldSize X fieldSize
int x; // 1 through fieldSize
char y; // 'a' through fieldSize
};
// contains ship's coordinates (location) and whether is was sunk
class ship{
public:
ship(); // void constructor, sets sunk=false
bool match(location&) const; // returns true if this location matches
// the ship's location
bool isSunk() const { return sunk; } // checks to see if the ship is sunk
void sink(); // sets "sunk" member variable of the ship to true
void setLocation(const location&); // deploys the ship at the specified location
void printShip() const; // prints location and status of the ship
private:
location loc;
bool sunk;
};
// contains the fleet of the deployed ships
class fleet{
public:
void deployFleet(); // deploys the ships in random locations
// of the ocean
bool operational() const; // returns true if at least
// one ship in the fleet is not sunk
bool isHitNSink(const location &); // returns true if there was a deployed
// ship at this location (hit) and sinks it
// otherwise returns false (miss)
void printFleet() const; // prints out locations of ships in fleet
private:
static const int fleetSize = 5; // number of battleships
int check(const location &); // returns index of the ship
// that matches location
// -1 if none match
ship ships[fleetSize]; // battleships of the fleet
};
#endif /* BATTLESHIP_H_ */
Here are my function definitions:
#include "battleship.h"
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
const int FLEET_SIZE = 5;
const int FIELD_SIZE = 5;
void location::pick(){
x = rand() % FIELD_SIZE;
if (x == 0){
x = 1;
}
y = rand() % FIELD_SIZE;
switch (y)
{
case 0:
y = 'A';
break;
case 1:
y = 'B';
break;
case 2:
y = 'C';
break;
case 3:
y = 'D';
break;
case 4:
y = 'E';
break;
}
}
void location::fire(void){
cout << "Enter the number of the grid to fire on ";
cin >>y;
cout << "Enter the letter of the grid to fire on ";
cin >> x;
}
void location::print() const{
cout << y << x;
}
bool compare(location one,location two){
if ((one.x == two.x)&&(one.y==two.y)){
return true;
}
return false;
}
location::location(){
x = -1;
}
void ship::setLocation(const location& location){
loc= location;
}
bool ship::match(location& location)const{
if (compare(loc, location)){
return true;
}
return false;
}
void ship::printShip()const{
cout << loc.print << endl;
cout << sunk << endl;
}
void ship::sink(){
sunk = true;
}
Here is the .cpp
#include "battleship.h"
#include <iostream>
#include <ctime>
#include <cstdlib>
using std::cout; using std::cin; using std::endl;
/// this is main function
const int FLEET_SIZE = 5;
const int FIELD_SIZE = 5;
int main(){
srand(time(NULL));
//
// checking location object
//
location mySpot, userShot;
mySpot.pick(); // selecting a new random location
cout << "Randomly selected location is: "; mySpot.print();
cout << "Input location: ";
userShot.fire(); // having user input a location
if (compare(mySpot, userShot))
cout << "Random location matches user input.\n";
else
cout << "Random location does not match user input.\n";
//
// checking ship object
//
ship myShip;
myShip.setLocation(mySpot); // placing ship at mySpot location
if(myShip.match(userShot))
cout << "myShip\'s location matches user input.\n";
else
cout << "myShip's location does not match user input.\n";
if(!myShip.isSunk()){
cout << "myship is not sunk yet, sinking it.\n";
myShip.sink();
}
cout << "myShip\'s status is: "; myShip.printShip();
//
// checking fleet object
//
/* // uncomment this part once you are done debugging above code
fleet myFleet;
myFleet.deployFleet(); // fleet is deployed at random locations
if(myFleet.operational())
cout << "Some ships of myFleet are still up.\n";
if(myFleet.isHitNSink(userShot))
cout << "there was a ship at userShot location, no it is sunk.\n";
else
cout << "there was no ship at userShot location.\n";
cout << "myFleet\'s status is: "; myFleet.printFleet();
*/
}
Here is the error for printShip() const
Error 1 error C3867: 'location::print': function call missing argument list; use '&location::print' to create a pointer to member
If someone could just explain what I need to edit in order to make printShip() const print the location of the ship as intended that is all need.
You are simply missing the parentheses in the call to location::print:
void ship::printShip() const {
cout << loc.print() << endl;
cout << sunk << endl;
}
It happens. But learn to recognize the message from your compiler: function call missing argument list actually means: "if you want to write a function call, add an argument list." And "use '&location::print' to create a pointer to member" tries to tell you the alternative, i.e., when you really want a pointer to the method, use &location::print.
Later
location::print() doesn't return anything, so you might want to change that. Or just use that call as it prints to cout right now.
void ship::printShip() const {
loc.print();
cout << endl;
cout << sunk << endl;
}

Storing a objects derived from an abstract base class with maps in a vector array of base class pointers

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!
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 <=