Классы в C++ [Урок 10] | Разработка игровых платформ
  1. Доброго времени суток. В связи с появлением спамеров, активация функций новых пользователей (Создавать темы, писать сообщения), теперь будет только после проверки администратором! Для регистрации отписываемся в лс, в вк. vk.com/tehnik777 (Пишем только с реальных страниц)
    Скрыть объявление

Классы в C++ [Урок 10]

Тема в разделе "С++/С#, HTML, PHP, JavaScript, XML...", создана пользователем Zloo, 6 ноя 2016.

Обсуждение темы Классы в C++ [Урок 10] в разделе С++/С#, HTML, PHP, JavaScript, XML... на форуме zetta-forum.ru.

  1. Zloo

    Zloo Администратор Команда форума

    Регистрация:
    31 окт 2016
    Сообщения:
    265
    Симпатии:
    158
    Баллы:
    43
    Пол:
    Мужской
    Сайт:
    https://zetta-forum.ru
    VK:
    https://vk.com/tehnik777
    Классы в C++ [Урок 10]

    Весь реальный мир состоит из объектов. Города состоят из районов, в каждом районе есть свои названия улиц, на каждой улице находятся жилые дома, которые также состоят из объектов.

    Практически любой материальный предмет можно представить в виде совокупности объектов, из которых он состоит. Допустим, что нам нужно написать программу для учета успеваемости студентов. Можно представить группу студентов, как класс языка C++. Назовем его Students.


    Код:
    class Students {
        // Имя студента
        std::string name;
        // Фамилия
        std::string last_name;
        // Пять промежуточных оценок студента
        int scores[5];
        // Итоговая оценка за семестр
        float average_ball;
    };
    

    Основные понятия

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

    У каждого студента есть имя — name и фамилия last_name . Также, у него есть промежуточные оценки за весь семестр. Эти оценки мы будем записывать в целочисленный массив из пяти элементов. После того, как все пять оценок будут проставлены, определим средний балл успеваемости студента за весь семестр — свойство average_ball.

    Методы — это функции, которые могут выполнять какие-либо действия над данными (свойствами) класса. Добавим в наш класс функцию calculate_average_ball(), которая будет определять средний балл успеваемости ученика.

    Методы класса — это его функции.
    Свойства класса — его переменные.



    Код:
    class Students {
        public:
            // Функция, считающая средний балл
            void calculate_average_ball()
            {
                int sum = 0; // Сумма всех оценок
                for (int i = 0; i < 5; ++i) {
                    sum += scores;
                }
                // считаем среднее арифметическое
                average_ball = sum / 5.0;
            }
    
            // Имя студента
            std::string name;
            // Фамилия
            std::string last_name;
            // Пять промежуточных оценок студента
            int scores[5];
    
        private:
            // Итоговая оценка за семестр
            float average_ball;
    };
    



    Функция calculate_average_ball() просто делит сумму всех промежуточных оценок на их количество.

    Модификаторы доступа public и private

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

    Закрытые данные класса размещаются после модификатора доступа private. Если отсутствует модификатор public, то все функции и переменные, по умолчанию являются закрытыми (как в первом примере).

    Обычно, приватными делают все свойства класса, а публичными — его методы. Все действия с закрытыми свойствами класса реализуются через его методы.

    Рассмотрим следующий код.


    Код:
    class Students {
        public:
            // Установка среднего балла
            void set_average_ball(float ball)
            {
                average_ball = ball;
            }
            // Получение среднего балла
            float get_average_ball()
            {
                return average_ball;
            }
            std::string name;
            std::string last_name;
            int scores[5];
    
        private:
            float average_ball;
    };
    

    Мы не можем напрямую обращаться к закрытым данными класса. Работать с этими данными можно только посредством методов этого класса. В примере выше, мы используем функцию get_average_ball() для получения средней оценки студента, и set_average_ball() для выставления этой оценки.

    Функция set_average_ball() принимает средний балл в качестве параметра и присваивает его значение закрытой переменной average_ball. Функция get_average_ball() просто возвращает значение этой переменной.

    Программа учета успеваемости студентов

    Создадим программу, которая будет заниматься учетом успеваемости студентов в группе. Создайте заголовочный файл students.h, в котором будет находиться класс Students.


    Код:
    /* students.h */
    #include <string>
    
    class Students {
        public:
            // Установка имени студента
            void set_name(std::string student_name)
            {
                name = student_name;
            }
            // Получение имени студента
            std::string get_name()
            {
                return name;
            }
            // Установка фамилии студента
            void set_last_name(std::string student_last_name)
            {
                last_name = student_last_name;
            }
            // Получение фамилии студента
            std::string get_last_name()
            {
                return last_name;
            }
            // Установка промежуточных оценок
            void set_scores(int student_scores[])
            {
                for (int i = 0; i < 5; ++i) {
                    scores = student_scores;
                }
            }
            // Установка среднего балла
            void set_average_ball(float ball)
            {
                average_ball = ball;
            }
            // Получение среднего балла
            float get_average_ball()
            {
                return average_ball;
            }
    
        private:
            // Промежуточные оценки
            int scores[5];
            // Средний балл
            float average_ball;
            // Имя
            std::string name;
            // Фамилия
            std::string last_name;
    };
    



    Мы добавили в наш класс новые методы, а также сделали приватными все его свойства. Функция set_name() сохраняет имя студента в переменной name, а get_name() возвращает значение этой переменной. Принцип работы функций set_last_name() и get_last_name() аналогичен.

    Функция set_scores() принимает массив с промежуточными оценками и сохраняет их в приватную переменную int scores[5].

    Теперь создайте файл main.cpp со следующим содержимым.


    Код:
    /* main.cpp */
    #include <iostream>
    #include "students.h"
    
    int main()
    {
        // Создание объекта класса Student
        Students student;
    
        std::string name;
        std::string last_name;
    
        // Ввод имени с клавиатуры
        std::cout << "Name: ";
        getline(std::cin, name);
    
        // Ввод фамилии
        std::cout << "Last name: ";
        getline(std::cin, last_name);
    
        // Сохранение имени и фамилии в объект класса Students
        student.set_name(name);
        student.set_last_name(last_name);
    
        // Оценки
        int scores[5];
        // Сумма всех оценок
        int sum = 0;
    
        // Ввод промежуточных оценок
        for (int i = 0; i < 5; ++i) {
            std::cout << "Score " << i+1 << ": ";
            std::cin >> scores;
            // суммирование
            sum += scores;
        }
    
        // Сохраняем промежуточные оценки в объект класса Student
        student.set_scores(scores);
        // Считаем средний балл
        float average_ball = sum / 5.0;
        // Сохраняем средний балл в объект класса Students
        student.set_average_ball(average_ball);
        // Выводим данные по студенту
        std::cout << "Average ball for " << student.get_name() << " "
             << student.get_last_name() << " is "
             << student.get_average_ball() << std::endl;
    
        return 0;
    }
    



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

    Объект класса Students характеризует конкретного студента. Если мы захотим выставить оценки всем ученикам в группе, то будем создавать новый объект для каждого из них. Использование классов очень хорошо подходит для описания объектов реального мира.

    После создания объекта student, мы вводим с клавиатуры фамилию, имя и промежуточные оценки для конкретного ученика. Пускай это будет Вася Пупкин, у которого есть пять оценок за семестр — две тройки, две четверки и одна пятерка.

    Введенные данные мы передаем set-функциям, которые присваивают их закрытым переменным класса. После того, как были введены промежуточные оценки, мы высчитываем средний балл на основе этих оценок, а затем сохраняем это значение в закрытом свойстве average_ball, с помощью функции set_average_ball().

    Скомпилируйте и запустите программу.

    [​IMG]

    Отделение данных от логики

    Вынесем реализацию всех методов класса в отдельный файл students.cpp


    Код:
    /* students.cpp */
    #include <string>
    #include "students.h"
    
    // Установка имени студента
    void Students::set_name(std::string student_name)
    {
        Students::name = student_name;
    }
    
    // Получение имени студента
    std::string Students::get_name()
    {
        return Students::name;
    }
    
    // Установка фамилии студента
    void Students::set_last_name(std::string student_last_name)
    {
        Students::last_name = student_last_name;
    }
    
    // Получение фамилии студента
    std::string Students::get_last_name()
    {
        return Students::last_name;
    }
    
    // Установка промежуточных оценок
    void Students::set_scores(int scores[])
    {
        for (int i = 0; i < 5; ++i) {
            Students::scores = scores;
        }
    }
    
    // Установка среднего балла
    void Students::set_average_ball(float ball)
    {
        Students::average_ball = ball;
    }
    
    // Получение среднего балла
    float Students::get_average_ball()
    {
        return Students::average_ball;
    }
    



    А в заголовочном файле students.h оставим только прототипы этих методов


    Код:
    /* students.h */
    #pragma once /* Защита от двойного подключения заголовочного файла */
    #include <string>
    
    class Students {
        public:
            // Установка имени студента
            void set_name(std::string);
            // Получение имени студента
            std::string get_name();
            // Установка фамилии студента
            void set_last_name(std::string);
            // Получение фамилии студента
            std::string get_last_name();
            // Установка промежуточных оценок
            void set_scores(int []);
            // Установка среднего балла
            void set_average_ball(float);
            // Получение среднего балла
            float get_average_ball();
    
        private:
            // Промежуточные оценки
            int scores[5];
            // Средний балл
            float average_ball;
            // Имя
            std::string name;
            // Фамилия
            std::string last_name;
    };
    

    Такой подход называется абстракцией данных — одного из фундаментальных принципов объектно-ориентированного программирования. К примеру, если кто-то другой захочет использовать наш класс в своем коде, ему не обязательно знать, как именно высчитывается средний балл. Он просто будет использовать функцию calculate_average_ball() из второго примера, не вникая в алгоритм ее работы.

    Над крупными проектами обычно работает несколько программистов. Каждый из них занимается написанием определенной части продукта. В таких масштабах кода, одному человеку практически нереально запомнить, как работает каждая из внутренних функций проекта. В нашей программе, мы используем оператор потокового вывода cout, не задумываясь о том, как он реализован на низком уровне. Кроме того, отделение данных от логики является хорошим тоном программирования.

    В начале обучения мы говорили о пространствах имен (namespaces). Каждый класс в C++ использует свое пространство имен. Это сделано для того, чтобы избежать конфликтов при именовании переменных и функций. В файле students.cpp мы используем оператор принадлежности :: перед именем каждой функции. Это делается для того, чтобы указать компилятору, что эти функции принадлежат классу Students.

    Создание объекта через указатель

    При создании объекта, лучше не копировать память для него, а выделять ее в в куче с помощью указателя. И освобождать ее после того, как мы закончили работу с объектом. Реализуем это в нашей программе, немного изменив содержимое файла main.cpp


    Код:
    /* main.cpp */
    #include <iostream>
    #include "students.h"
    
    int main()
    {
        // Выделение памяти для объекта Students
        Students *student = new Students;
    
        std::string name;
        std::string last_name;
    
        // Ввод имени с клавиатуры
        std::cout << "Name: ";
        getline(std::cin, name);
    
        // Ввод фамилии
        std::cout << "Last name: ";
        getline(std::cin, last_name);
    
        // Сохранение имени и фамилии в объект класса Students
        student->set_name(name);
        student->set_last_name(last_name);
    
        // Оценки
        int scores[5];
        // Сумма всех оценок
        int sum = 0;
    
        // Ввод промежуточных оценок
        for (int i = 0; i < 5; ++i) {
            std::cout << "Score " << i+1 << ": ";
            std::cin >> scores;
            // суммирование
            sum += scores;
        }
        // Сохраняем промежуточные оценки в объект класса Student
        student->set_scores(scores);
    
        // Считаем средний балл
        float average_ball = sum / 5.0;
        // Сохраняем средний балл в объект класса Students
        student->set_average_ball(average_ball);
        // Выводим данные по студенту
        std::cout << "Average ball for " << student->get_name() << " "
             << student->get_last_name() << " is "
             << student->get_average_ball() << std::endl;
        // Удаление объекта student из памяти
        delete student;
        return 0;
    }
    



    При создании статического объекта, для доступа к его методам и свойствам, используют операция прямого обращения — «.» (символ точки). Если же память для объекта выделяется посредством указателя, то для доступа к его методам и свойствам используется оператор косвенного обращения — «->».

    Конструктор и деструктор класса

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


    Код:
    class Students {
        public:
            // Конструктор класса Students
            Students(int default_score)
            {
                for (int i = 0; i < 5; ++i) {
                    scores = default_score;
                }
            }
    
        private:
            int scores[5];
    };
    
    int main()
    {
        // Передаем двойку в конструктор
        Students *student = new Students(2);
        return 0;
    }
    



    Мы можем исправить двойки, если ученик будет хорошо себя вести, и вовремя сдавать домашние задания. А на «нет» и суда нет :)

    Деструктор класса вызывается при уничтожении объекта. Имя деструктора аналогично имени конструктора, только в начале ставится знак тильды ~. Деструктор не имеет входных параметров.


    Код:
    #include <iostream>
    
    class Students {
        public:
            // Деструктор
            ~Students()
            {
                std::cout << "Memory has been cleaned. Good bye." << std::endl;
            }
    };
    
    int main()
    {
        Students *student = new Students;
        // Уничтожение объекта
        delete student;
        return 0;
    }
    
     

Поделиться этой страницей