Menu
Coddy logo textTech

Итоги — Система учета студентов

Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy — урок 39 из 104.

Пришло время применить ваши знания об инкапсуляции на практике! В этом испытании вы создадите Систему учета студентов, которая демонстрирует правильное использование спецификаторов доступа, сокрытие информации и вложенные классы.

Ваша система будет управлять данными студентов, используя следующие принципы инкапсуляции:

  • Закрытые члены данных (Private data members) для защиты конфиденциальной информации, такой как оценки и идентификаторы студентов
  • Открытый интерфейс (Public interface) с геттерами и контролируемыми сеттерами
  • Вложенный класс для представления оценок по отдельным курсам, что позволяет скрыть детали реализации внутри класса студента

Вот структура, которую вам предстоит реализовать:

class Student {
public:
    class Grade {    // Вложенный класс для оценок по курсам
        // ...
    };
    
    // Открытый интерфейс для взаимодействия с данными студента
    
private:
    std::string name;
    int studentId;
    // Коллекция оценок
};

Это испытание объединяет все темы из этой главы: выбор подходящих уровней доступа, сокрытие деталей реализации за чистым интерфейсом и использование вложенных классов для организации связанных типов. Тщательно продумайте, что должно быть доступно, а что должно оставаться скрытым.

challenge icon

Задание

Легко

Давайте создадим систему учета студентов, которая объединит все, что вы узнали об инкапсуляции. Вы создадите систему, в которой данные студентов надежно защищены, оценки управляются через вложенный класс, а все взаимодействие происходит через чистый публичный интерфейс.

Для организации кода вы создадите два файла:

  • Student.h: Определите класс Student, который демонстрирует правильную инкапсуляцию с вложенным классом Grade.

    Ваш вложенный класс Grade (объявленный в публичной секции Student) должен хранить название курса (string) и оценку (double). Создайте для него конструктор, принимающий оба значения, и предоставьте методы getCourseName() и getScore() для доступа к данным. Класс Grade хранит свои данные в приватной секции — даже будучи вложенным в Student, он сохраняет собственную инкапсуляцию.

    Класс Student должен иметь приватные члены для имени студента (string), идентификатора студента (int) и коллекции указателей на Grade. Реализуйте:

    • Конструктор, принимающий имя и идентификатор студента
    • Геттеры getName() и getStudentId() (оба const)
    • Метод addGrade(const std::string& course, double score), который создает новый объект Grade и добавляет его в запись студента (добавляйте только если оценка находится в диапазоне от 0 до 100 включительно)
    • Метод getAverageGrade() (const), который вычисляет и возвращает средний балл всех оценок или 0.0, если оценок нет
    • Метод displayRecord() (const), который показывает полную запись студента

    Не забудьте очистить динамически выделенную память для оценок в деструкторе и включить соответствующие guard-заголовки.

  • main.cpp: Считайте имя студента, идентификатор студента и три оценки за курсы из входных данных. Формат ввода будет состоять из пяти строк: имя, ID, затем три строки, каждая из которых содержит название курса и оценку, разделенные пробелом (например, Math 95.5).

    Создайте объект Student с именем и ID, добавьте все три оценки, а затем отобразите полную запись.

    Формат вывода для displayRecord() должен быть следующим:

    Student: <name> (ID: <id>)
    Grades:
      <course1>: <score1>
      <course2>: <score2>
      <course3>: <score3>
    Average: <average>

Форматируйте все оценки и средний балл с одним десятичным знаком, используя std::fixed и std::setprecision(1) из библиотеки <iomanip>. Преобразуйте ID с помощью std::stoi(), а оценки — с помощью std::stod().

Эта задача объединяет приватные члены данных, публичные геттеры, контролируемые сеттеры с валидацией и вложенный класс — все это работает вместе для создания хорошо инкапсулированной системы учета студентов.

Шпаргалка

Инкапсуляция объединяет спецификаторы доступа, сокрытие информации и вложенные классы для защиты данных и организации кода.

Спецификаторы доступа для защиты данных

Используйте private для конфиденциальных членов данных и public для интерфейса:

class Student {
public:
    // Публичные методы интерфейса
    
private:
    std::string name;
    int studentId;
    // Другие приватные данные
};

Вложенные классы

Вложенные классы организуют связанные типы внутри класса, сохраняя собственную инкапсуляцию:

class Student {
public:
    class Grade {    // Вложенный класс
    private:
        std::string courseName;
        double score;
    public:
        Grade(const std::string& course, double s) 
            : courseName(course), score(s) {}
        std::string getCourseName() const { return courseName; }
        double getScore() const { return score; }
    };
    
private:
    std::vector<Grade*> grades;
};

Контролируемый доступ с валидацией

Методы могут проверять данные перед изменением приватных членов:

void addGrade(const std::string& course, double score) {
    if (score >= 0 && score <= 100) {
        grades.push_back(new Grade(course, score));
    }
}

Константные методы

Помечайте методы, которые не изменяют данные, как const:

std::string getName() const { return name; }
double getAverageGrade() const {
    // Вычислить и вернуть среднее значение
}

Управление памятью

Освобождайте динамически выделенную память для объектов в деструкторе:

~Student() {
    for (Grade* grade : grades) {
        delete grade;
    }
}

Попробуйте сами

#include <iostream>
#include <string>
#include <sstream>
#include "Student.h"

int main() {
    // Считать имя студента
    std::string name;
    std::getline(std::cin, name);
    
    // Считать ID студента
    std::string idStr;
    std::getline(std::cin, idStr);
    int studentId = std::stoi(idStr);
    
    // Считать оценки по трем курсам (формат: "CourseName Score")
    std::string line1, line2, line3;
    std::getline(std::cin, line1);
    std::getline(std::cin, line2);
    std::getline(std::cin, line3);
    
    // TODO: Разобрать каждую строку, чтобы извлечь название курса и оценку
    // Используйте std::stod() для преобразования строк с оценками в double
    
    // TODO: Создать объект Student с именем и ID
    
    // TODO: Добавить все три оценки студенту
    
    // TODO: Вывести полную запись о студенте
    
    return 0;
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование