Degree and Non-degree seeking Students

Problem

  • Write a program for BYYou University Registrar to keep student profiles
  • BYYou University offers courses, but not degrees
  • A BYYou student has
    • a name
    • a unique student ID
    • a list of courses
  • Courses are worth 3 credits each and can only be taken once

Part I

  • Create a class that contains data members for
    • a name
    • a unique student ID
    • a list of courses
  • Member functions should include functionality to
    • check if a course has been taken
    • get total credits taken
    • add a course to the course list
    • get a string representation as seen here: Jane Doe; ID# 159817; 35 credits
  • Note that the ID is assigned by the program

Part II

  • Your program should have two phases:
    • Input new students (until the user enters “END”)
    • Output student summary
  • The Input phase should
    • Prompt for a student name
    • Prompt for a list of courses taken (again, use “END” as a sentinel)
  • The Output phase should
    • Display the list of input students with name, ID, and credits taken for each student as so:
    • Jane Doe; ID# 159817; 35 credits

Part III

  • Great news! BYYou now offers a number of Bachelor degrees!
  • Create a Degree-Seeking Student class which includes
    • a program name
    • a credit requirement (for graduation)
  • This derived class should include functionality to test if a student is eligible to graduate
  • The student summary should also include the program name, credit requirement, and eligibility for graduation

Part IV

  • Allow the Registrar to input a new student’s program name and credit requirement (or “NONE” if student is non-degree seeking)
  • Make an object of the base or derived class appropriate to whether the student is degree-seeking

Solution

Source.cpp

/*
Examples of test case classes include (you should have specific test cases):
Test cases should create both a degree-seeking and a non-degree seeking student
 
They should try to add classes that have already been added
 
They should create degree-seeking students that are both eligible and ineligible to graduate (check border cases)
 
They should test when no students are added
*/
 
#include <iostream>
#include <string>
#include "DegreeStudent.h"
#include "Student.h"
 
using namespace std;
 
Student * create_student(string name);
 
int main()
{
	vector<Student *> students;
 
	/* BASE CLASS TEST CODE
	Student * student_A = new Student("Harry Potter");
	Student * student_B = new Student("Hermione Granger");
 
	student_A->add_course("Potions");
	cout << student_A->to_string() << endl;
	cout << student_B->to_string() << endl;
	*/
 
	/* DERIVED CLASS TEST CODE
	DegreeStudent * ds_student_C = new DegreeStudent("Neville Longbottom", "Herbology", 2);
	ds_student_C->add_course("Herbology 101");
 
	cout << ds_student_C->to_string() << endl;
 
	// A DegreeStudent IS-A Student, thus by the substitution principle we can put a 
	// DegreeStudent * where a Student * is expected
	Student * student_ptr = ds_student_C;
 
	// Without "virtual", this would call the to_string() function of the base class
	// With "virtual", the to_string() function of the more specific class is called
	cout << student_ptr->to_string() << endl;
 
	// We can call is_eligible_to_graduate() because ds_student_C is of type DegreeStudent *
	// If ds_student_C were of type Student *, we could not because a Student object 
	// (or even a DegreeStudent object being pointed to by a Student *) doesn't have that function
	if (ds_student_C->is_eligible_to_graduate())
	{
		cout << "Mmmm, graduate you will" << endl;
	}
	// The substitution principle allows us to put a DegreeStudent * any place that a Student * is expected
	students.push_back(ds_student_C);
 
	system("pause");
	*/
 
	// 1. INPUT STUDENTS AND THEIR COURSES
	string input;
 
	cout << "Student name: ";
	getline(cin, input);
	while (input != "END")
	{
		//remember, create_student is a static function, not a class member function
		Student * new_student = create_student(input);
		students.push_back(new_student);
 
		cout << endl;
 
		cout << "Student name: ";
		getline(cin, input);
	}
 
	cout << "***********************" << endl;
	// 2. OUTPUT STUDENT SUMMARIES
	for (int i = 0; i < students.size(); i++)
	{
		// With "virtual" the more specific to_string() function will be called,
		// depending on whether students[i] points to a Student object or a DegreeStudent
		cout << students[i]->to_string() << endl;
	}
 
	system("pause");
	return 0;
}
 
Student * create_student(string name)
{
	//This pointer will be what we return from the function and needs to 
	//initialized appropriately depending on the user's input to a Student *  or a DegreeStudent *
	Student * new_student = NULL;
 
	string input;
	cout << "Program: ";
	getline(cin, input);
 
	if (input == "NONE")
	{
		// No program means the student is not degree-seeking
		new_student = new Student(name);
	}
	else
	{
		// Otherwise student is degree seeking and we need more info
		int credit_requirement;
		cout << "Credits required: ";
		cin >> credit_requirement;
		cin.sync(); // We used cin >>, so we need to read the '\n' character
 
		// By the substitution principle, we can put a DegreeStudent * in for a Student *
		// Remember, a DegreeStudent IS-A Student
		new_student = new DegreeStudent(name, input, credit_requirement);
	}
 
	cout << "Course taken: ";
	getline(cin, input);
 
	while (input != "END")
	{
		// Whether a DegreeStudent or just a Student, both have access to the base class function add_course()
		new_student->add_course(input);
 
		cout << "Course taken: ";
		getline(cin, input);
	}
 
	return new_student;
}

Student.h

#include <string>
#include <vector>
 
using namespace std;
 
// #pragma once is the same as #ifndef ..., #define ..., and #endif
#pragma once
class Student
{
public:
	// CONSTRUCTOR
	/*
	Constructor that creates a new Student object given a name
	@param name to assign to the new Student object
	*/
	Student(string _name);
 
	// OTHER MEMBER FUNCTIONS
	/*
	Test if *this* student has taken a course
	@param course name of course to test for
	@return true if course is in list of taken courses; false otherwise
	*/
	bool has_taken_course(string course) const;
 
	/*
	@return total credits, which is 3*number of courses taken
	*/
	int get_total_credits() const;
 
	/*
	Adds a course to list of courses taken IF and only if course has not already been taken
	@param course course name to add
	@return 0 if added; -1 if course already present
	*/
	int add_course(string course);
 
	/*
	@return a string representation of this String object
	*/
	//virtual means "check any derived class first to see if this is overwritten"
	virtual string to_string() const;
 
private:
	// DATA MEMBERS
	string name;
	int student_id;
	vector<string> course_list;
 
	// static variables exist once for all objects of the class
	static int next_id;
};

Student.cpp

#include <sstream>
#include "Student.h"
 
// Initialize the static variable
int Student::next_id = 0;
 
Student::Student(string _name)
{
	name = _name;
	student_id = next_id; // here is our static variable at work
	next_id++;
}
 
bool Student::has_taken_course(string course) const
{
	for (int i = 0; i < course_list.size(); i++)
	{
		if (course_list[i] == course)
		{
			return true;
		}
	}
 
	// Never found it
	return false;
}
 
int Student::get_total_credits() const
{
	// We assume all courses are the same number of credits
	return course_list.size() * 3;
}
 
int Student::add_course(string course)
{
	// Don't add course if it's already in the list
	if (has_taken_course(course))
	{
		return -1;
	}
	else
	{
		course_list.push_back(course);
		return 0;
	}
}
 
string Student::to_string() const
{
	// use ostringstream to build a string that is a composite of strings and other variable types
	ostringstream strm;
 
	strm << name << "; ID# " << student_id << "; " << get_total_credits() << " credits";
 
	return strm.str();
}

DegreeStudent.h

// To inherit from Student, we need to know what a Student is
#include "Student.h"
 
#pragma once
// this is where we specify that a DegreeStudent IS-A Student and inherits everything a Student has
class DegreeStudent : public Student 
{
public:
	// CONSTRUCTOR
	/*
	Constructor to make a DegreeStudent from a name, program, and a credit requirement
	@param _name name to give to *this* student
	@param _program_name name to assign to *this* student's program
	@param _credit_requirement value to set as *this* student's credit requirement
	*/
	DegreeStudent(string _name, string _program_name, int _credit_requirement);
 
	// OTHER MEMBER FUNCTIONS
	/*
	@return true if *this* student has taken greater than or equal to the credit requirement
	*/
	bool is_eligible_to_graduate() const;
 
	/*
	@return a string representation of *this* DegreeStudent objeect
	*/
	//virtual means "check any derived class first to see if this is overwritten"
	virtual string to_string() const;
 
private:
	// DATA MEMBERS
	string program_name;
	int credit_requirement;
 
	// Note that all other data members (e.g., name, id, course_list) are inherited
};

DegreeStudent.cpp

#include <sstream>
#include "DegreeStudent.h"
 
DegreeStudent::DegreeStudent(string _name, string _program_name, int _credit_requirement)
	:Student(_name), program_name(_program_name), credit_requirement(_credit_requirement)
	// Everything after the ':' is the initializer list and includes a call to the base class constructor
	// Otherwise we couldn't access the base class data members to initialize them
{
}
 
// OTHER MEMBER FUNCTIONS
bool DegreeStudent::is_eligible_to_graduate() const
{
	// This is a call to the base class member function
	// We don't need to specify Student:: because it's implied when there is no overwriting
	// function in the derived DegreeStudent class
	int total_credits = get_total_credits();
	return (total_credits >= credit_requirement);
}
 
string DegreeStudent::to_string() const
{
	// use ostringstream to build a string that is a composite of strings and other variable types
	ostringstream strm;
 
	// first we want what's already put together by the base class to_string() function
	strm << Student::to_string();
 
	// then we add stuff specific to the derived class
	strm << "; " << program_name << "; Credits required: " << credit_requirement;
 
	if (is_eligible_to_graduate())
	{
		strm << " - ELIGIBLE TO GRADUATE!";
	}
 
	return strm.str();
}
cs-142/degree-and-non-degree-seeking-students.txt · Last modified: 2015/06/09 13:00 by cs142ta
Back to top
CC Attribution-Share Alike 4.0 International
chimeric.de = chi`s home Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0