Lesson 1
Using Structures and Classes for a Simple Student Management System in C++
Introduction

Hello, Space Explorer! Today, we’re going to discuss a practical and essential topic in C++: managing data using structures and classes. To practice this concept, we will build a simple Student Management System. Specifically, we will create a class that stores students and their grades. This hands-on approach will help us understand how structures and classes can be used effectively in real-world applications. Are you excited? Great, let's dive in!

Introducing Methods to Implement

To accomplish our task, we need to implement three primary methods within our class:

  1. void add_student(std::string name, int grade): This method allows us to add a new student and their grade to our list. If the student is already on the list, their grade will be updated.
  2. std::optional<int> get_grade(std::string name): This method retrieves the grade for a student given their name. If the student is not found, it returns std::nullopt.
  3. bool remove_student(std::string name): This method removes a student from the list by their name. It returns true if the student was successfully removed and false if the student does not exist.

Does that sound straightforward? Fantastic, let's break it down step-by-step.

Implementing the Solution Step-by-Step

Let’s start by defining our StudentManager class, which will use a std::vector to manage students and their grades.

C++
1#include <iostream> 2#include <vector> 3#include <optional> 4#include <string> 5 6// Define the Student structure 7struct Student { 8 std::string name; 9 int grade; 10}; 11 12// Define the StudentManager class 13class StudentManager { 14public: 15 StudentManager() = default; 16 void add_student(std::string name, int grade); 17 std::optional<int> get_grade(std::string name); 18 bool remove_student(std::string name); 19 const std::vector<Student>& get_students() const; 20 21private: 22 std::vector<Student> students; 23};

To access the students in the StudentManager, we have a simple getter method get_students:

C++
1const std::vector<Student>& StudentManager::get_students() const { 2 return students; 3}

This method returns a constant reference to the students, providing read access to the list.

Step 1: Implementing `add_student`

The add_student method checks if a student already exists in our vector. If so, their grade is updated; otherwise, the student is added to the vector.

C++
1void StudentManager::add_student(std::string name, int grade) { 2 for (auto& student : students) { 3 if (student.name == name) { 4 student.grade = grade; 5 return; 6 } 7 } 8 students.push_back({name, grade}); 9}

Let's break it down:

  • Using a range-based for loop, we iterate through the students.
  • If we find a Student where the name matches the given name, we update the grade.
  • If not found, we append a new Student to our vector.

A question for you: Why do we need to check if the student already exists before appending? Correct. Preventing duplicate entries and ensuring data consistency is key!

Step 2: Implementing `get_grade`

The get_grade method searches for a student in the vector by name and returns their grade.

C++
1std::optional<int> StudentManager::get_grade(std::string name) { 2 for (const auto& student : students) { 3 if (student.name == name) { 4 return student.grade; 5 } 6 } 7 return std::nullopt; // Use std::nullopt when the value isn't found 8}

A brief explanation of std::optional:

  • std::optional is a C++17 feature that represents a value that might or might not be present.
  • If the student is found, we return their grade; if not, we return std::nullopt, indicating no value.
Step 3: Implementing `remove_student`

The remove_student method removes a student from the vector by their name and returns whether the operation was successful.

C++
1bool StudentManager::remove_student(std::string name) { 2 for (auto it = students.begin(); it != students.end(); ++it) { 3 if (it->name == name) { 4 students.erase(it); 5 return true; 6 } 7 } 8 return false; 9}

Here’s what happens:

  • We use an iterator to iterate through the students and check for a matching student name.
  • If a match is found, we delete the entry using erase and return true.
  • If no match is found by the end of the loop, we return false.

This method checks for presence before deletion, ensuring we only attempt to delete valid entries. Why is this check important? Yes, it prevents errors and helps maintain a reliable state.

The Final Solution

Let's combine all our steps. Here is the complete StudentManager class with all the methods integrated, including instantiation and method invocation to demonstrate usage:

C++
1#include <iostream> 2#include <vector> 3#include <optional> 4#include <string> 5 6struct Student { 7 std::string name; 8 int grade; 9}; 10 11class StudentManager { 12public: 13 StudentManager() = default; 14 15 void add_student(std::string name, int grade) { 16 for (auto& student : students) { 17 if (student.name == name) { 18 student.grade = grade; 19 return; 20 } 21 } 22 students.push_back({name, grade}); 23 } 24 25 std::optional<int> get_grade(std::string name) { 26 for (const auto& student : students) { 27 if (student.name == name) { 28 return student.grade; 29 } 30 } 31 return std::nullopt; 32 } 33 34 bool remove_student(std::string name) { 35 for (auto it = students.begin(); it != students.end(); ++it) { 36 if (it->name == name) { 37 students.erase(it); 38 return true; 39 } 40 } 41 return false; 42 } 43 44 const std::vector<Student>& get_students() const { 45 return students; 46 } 47 48private: 49 std::vector<Student> students; 50}; 51 52int main() { 53 StudentManager manager; 54 55 // Add students 56 manager.add_student("Alice", 85); 57 manager.add_student("Bob", 90); 58 for (const auto& student : manager.get_students()) { 59 std::cout << "Student: " << student.name << ", Grade: " << student.grade << std::endl; 60 } 61 // Output: Student: Alice, Grade: 85 62 // Student: Bob, Grade: 90 63 64 // Update an existing student's grade 65 manager.add_student("Alice", 95); 66 for (const auto& student : manager.get_students()) { 67 std::cout << "Student: " << student.name << ", Grade: " << student.grade << std::endl; 68 } 69 // Output: Student: Alice, Grade: 95 70 // Student: Bob, Grade: 90 71 72 // Retrieve a student's grade 73 if (auto grade = manager.get_grade("Bob")) { 74 std::cout << "Bob's grade: " << *grade << std::endl; // Output: 90 75 } 76 77 // Attempt to retrieve a non-existent student's grade 78 if (auto grade = manager.get_grade("Charlie")) { 79 std::cout << "Charlie's grade: " << *grade << std::endl; 80 } else { 81 std::cout << "Charlie not found\n"; // Output: Charlie not found 82 } 83 84 // Remove a student 85 if (manager.remove_student("Alice")) { 86 std::cout << "Alice removed successfully\n"; // Output: Alice removed successfully 87 } 88 for (const auto& student : manager.get_students()) { 89 std::cout << "Student: " << student.name << ", Grade: " << student.grade << std::endl; 90 } 91 // Output: Student: Bob, Grade: 90 92 93 // Attempt to remove a non-existent student 94 if (!manager.remove_student("David")) { 95 std::cout << "David does not exist\n"; // Output: David does not exist 96 } 97 98 return 0; 99}

Reviewing this final solution confirms that we have a robust way to manage our list of students efficiently.

Lesson Summary

In this lesson, we created a StudentManager class to manage students and their grades using C++ structures and vectors. We implemented three essential methods — add_student, get_grade, and remove_student. Each method illustrated key programming paradigms, including iteration, condition checking, and simple data manipulation.

We also demonstrated how to instantiate the StudentManager class and invoke its methods, illustrating how these operations can be used in practice.

By completing this exercise, you have fortified your knowledge of using structures, classes, and vectors in practical applications. I encourage you to continue practicing these concepts by extending the class with new features or experimenting with similar problems. Always remember — practice makes perfect! Happy coding!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.