Классы в C++ — урок 10

5 ответ(ов) в теме
Daneilux
не в сети давно
На сайте с 08.01.2014
Участник
0
01:02

Весь реальный мир состоит из объектов. Города состоят из районов, в каждом районе есть свои названия улиц, на каждой улице находятся жилые дома, которые также состоят из объектов.
Практически любой материальный предмет можно представить в виде совокупности объектов, из которых он состоит. Допустим, что нам нужно написать программу для учета успеваемости студентов. Можно представить группу студентов, как класс языка C++. Назовем его Students.
class Students {<br> // Имя студента<br> std::string name;<br> // Фамилия<br> std::string last_name;<br> // Пять промежуточных оценок студента<br> int scores[5];<br> // Итоговая оценка за семестр<br> float average_ball;<br>};
Основные понятия
Классы в программировании состоят из свойств и методов. Свойства — это любые данные, которыми можно характеризовать объект класса. В нашем случае, объектом класса является студент, а его свойствами — имя, фамилия, оценки и средний балл.
У каждого студента есть имя — name и фамилия last_name . Также, у него есть промежуточные оценки за весь семестр. Эти оценки мы будем записывать в целочисленный массив из пяти элементов. После того, как все пять оценок будут проставлены, определим средний балл успеваемости студента за весь семестр — свойство average_ball.
Методы — это функции, которые могут выполнять какие-либо действия над данными (свойствами) класса. Добавим в наш класс функцию calculate_average_ball(), которая будет определять средний балл успеваемости ученика.
- Методы класса — это его функции.
- Свойства класса — его переменные.
class Students {<br> public:<br> // Функция, считающая средний балл<br> void calculate_average_ball()<br> {<br> int sum = 0; // Сумма всех оценок<br> for (int i = 0; i < 5; ++i) {<br> sum += scores<em>;<br> }<br> // считаем среднее арифметическое<br> average_ball = sum / 5.0;<br> }<br><br> // Имя студента<br> std::string name;<br> // Фамилия<br> std::string last_name;<br> // Пять промежуточных оценок студента<br> int scores[5];<br><br> private:<br> // Итоговая оценка за семестр<br> float average_ball;<br>};
Функция [i]calculate_average_ball() просто делит сумму всех промежуточных оценок на их количество.
Модификаторы доступа public и private
Все свойства и методы классов имеют права доступа. По умолчанию, все содержимое класса является доступным для чтения и записи только для него самого. Для того, чтобы разрешить доступ к данным класса извне, используют модификатор доступа public. Все функции и переменные, которые находятся после модификатора public, становятся доступными из всех частей программы.
Закрытые данные класса размещаются после модификатора доступа private. Если отсутствует модификатор public, то все функции и переменные, по умолчанию являются закрытыми (как в первом примере).
Обычно, приватными делают все свойства класса, а публичными — его методы. Все действия с закрытыми свойствами класса реализуются через его методы. Рассмотрим следующий код.
class Students {<br> public:<br> // Установка среднего балла<br> void set_average_ball(float ball)<br> {<br> average_ball = ball;<br> }<br> // Получение среднего балла<br> float get_average_ball()<br> {<br> return average_ball;<br> }<br> std::string name;<br> std::string last_name;<br> int scores[5];<br><br> private:<br> float average_ball;<br>};
Мы не можем напрямую обращаться к закрытым данными класса. Работать с этими данными можно только посредством методов этого класса. В примере выше, мы используем функцию get_average_ball() для получения средней оценки студента, и set_average_ball() для выставления этой оценки.
Функция set_average_ball() принимает средний балл в качестве параметра и присваивает его значение закрытой переменной average_ball. Функция get_average_ball() просто возвращает значение этой переменной.
Программа учета успеваемости студентов
Создадим программу, которая будет заниматься учетом успеваемости студентов в группе. Создайте заголовочный файл students.h, в котором будет находиться класс Students.
/* students.h */<br>#include <string><br><br>class Students {<br> public:<br> // Установка имени студента<br> void set_name(std::string student_name)<br> {<br> name = student_name;<br> }<br> // Получение имени студента<br> std::string get_name()<br> {<br> return name;<br> }<br> // Установка фамилии студента<br> void set_last_name(std::string student_last_name)<br> {<br> last_name = student_last_name;<br> }<br> // Получение фамилии студента<br> std::string get_last_name()<br> {<br> return last_name;<br> }<br> // Установка промежуточных оценок<br> void set_scores(int student_scores[])<br> {<br> for (int i = 0; i < 5; ++i) {<br> scores<em> = student_scores[i];<br> }<br> }<br> // Установка среднего балла<br> void set_average_ball(float ball)<br> {<br> average_ball = ball;<br> }<br> // Получение среднего балла<br> float get_average_ball()<br> {<br> return average_ball;<br> }<br><br> private:<br> // Промежуточные оценки<br> int scores[5];<br> // Средний балл<br> float average_ball; <br> // Имя<br> std::string name;<br> // Фамилия<br> std::string last_name;<br>};
Мы добавили в наш класс новые методы, а также сделали приватными все его свойства. Функция [i]set_name() сохраняет имя студента в переменной name, а get_name() возвращает значение этой переменной. Принцип работы функций set_last_name() и get_last_name() аналогичен.
Функция set_scores() принимает массив с промежуточными оценками и сохраняет их в приватную переменную int scores[5].
Теперь создайте файл main.cpp со следующим содержимым.
/* main.cpp */<br>#include <iostream><br>#include "students.h"<br><br>int main()<br>{<br> // Создание объекта класса Student<br> Students student;<br><br> std::string name;<br> std::string last_name;<br><br> // Ввод имени с клавиатуры<br> std::cout << "Name: ";<br> getline(std::cin, name);<br><br> // Ввод фамилии<br> std::cout << "Last name: ";<br> getline(std::cin, last_name);<br><br> // Сохранение имени и фамилии в объект класса Students<br> student.set_name(name);<br> student.set_last_name(last_name);<br><br> // Оценки<br> int scores[5];<br> // Сумма всех оценок<br> int sum = 0;<br><br> // Ввод промежуточных оценок <br> for (int i = 0; i < 5; ++i) {<br> std::cout << "Score " << i+1 << ": ";<br> std::cin >> scores<em>;<br> // суммирование<br> sum += scores[i];<br> }<br><br> // Сохраняем промежуточные оценки в объект класса Student<br> student.set_scores(scores);<br> // Считаем средний балл<br> float average_ball = sum / 5.0;<br> // Сохраняем средний балл в объект класса Students<br> student.set_average_ball(average_ball);<br> // Выводим данные по студенту<br> std::cout << "Average ball for " << student.get_name() << " "<br> << student.get_last_name() << " is "<br> << student.get_average_ball() << std::endl;<br><br> return 0;<br>}
В самом начале программы создается объект класса [i]Students. Дело в том, что сам класс является только описанием его объекта. Класс Students является описанием любого из студентов, у которого есть имя, фамилия и возможность получения оценок.
Объект класса Students характеризует конкретного студента. Если мы захотим выставить оценки всем ученикам в группе, то будем создавать новый объект для каждого из них. Использование классов очень хорошо подходит для описания объектов реального мира.
После создания объекта student, мы вводим с клавиатуры фамилию, имя и промежуточные оценки для конкретного ученика. Пускай это будет Вася Пупкин, у которого есть пять оценок за семестр — две тройки, две четверки и одна пятерка.
Введенные данные мы передаем set-функциям, которые присваивают их закрытым переменным класса. После того, как были введены промежуточные оценки, мы высчитываем средний балл на основе этих оценок, а затем сохраняем это значение в закрытом свойстве average_ball, с помощью функции set_average_ball().
Скомпилируйте и запустите программу.
Форум
Отделение данных от логики
Вынесем реализацию всех методов класса в отдельный файл students.cpp.
/* students.cpp */<br>#include <string><br>#include "students.h"<br><br>// Установка имени студента<br>void Students::set_name(std::string student_name)<br>{<br> Students::name = student_name;<br>}<br><br>// Получение имени студента<br>std::string Students::get_name()<br>{<br> return Students::name;<br>}<br><br>// Установка фамилии студента<br>void Students::set_last_name(std::string student_last_name)<br>{<br> Students::last_name = student_last_name;<br>}<br><br>// Получение фамилии студента<br>std::string Students::get_last_name()<br>{<br> return Students::last_name;<br>}<br><br>// Установка промежуточных оценок<br>void Students::set_scores(int scores[])<br>{<br> for (int i = 0; i < 5; ++i) {<br> Students::scores<em> = scores[i];<br> }<br>}<br><br>// Установка среднего балла<br>void Students::set_average_ball(float ball)<br>{<br> Students::average_ball = ball;<br>}<br><br>// Получение среднего балла<br>float Students::get_average_ball()<br>{<br> return Students::average_ball;<br>}
А в заголовочном файле students.h оставим только прототипы этих методов.
/* students.h */<br>#pragma once /* Защита от двойного подключения заголовочного файла */<br>#include <string><br><br>class Students {<br> public:<br> // Установка имени студента<br> void set_name(std::string);<br> // Получение имени студента<br> std::string get_name();<br> // Установка фамилии студента<br> void set_last_name(std::string);<br> // Получение фамилии студента<br> std::string get_last_name();<br> // Установка промежуточных оценок<br> void set_scores(int []);<br> // Установка среднего балла<br> void set_average_ball(float);<br> // Получение среднего балла<br> float get_average_ball();<br><br> private:<br> // Промежуточные оценки<br> int scores[5];<br> // Средний балл<br> float average_ball;<br> // Имя<br> std::string name;<br> // Фамилия<br> std::string last_name;<br>};
Такой подход называется абстракцией данных — одного из фундаментальных принципов объектно-ориентированного программирования. К примеру, если кто-то другой захочет использовать наш класс в своем коде, ему не обязательно знать, как именно высчитывается средний балл. Он просто будет использовать функцию [i]calculate_average_ball() из второго примера, не вникая в алгоритм ее работы.
Над крупными проектами обычно работает несколько программистов. Каждый из них занимается написанием определенной части продукта. В таких масштабах кода, одному человеку практически нереально запомнить, как работает каждая из внутренних функций проекта. В нашей программе, мы используем оператор потокового вывода cout, не задумываясь о том, как он реализован на низком уровне. Кроме того, отделение данных от логики является хорошим тоном программирования.
В начале обучения мы говорили о пространствах имен (namespaces). Каждый класс в C++ использует свое пространство имен. Это сделано для того, чтобы избежать конфликтов при именовании переменных и функций. В файле students.cpp мы используем оператор принадлежности :: перед именем каждой функции. Это делается для того, чтобы указать компилятору, что эти функции принадлежат классу Students.
Создание объекта через указатель
При создании объекта, лучше не копировать память для него, а выделять ее в в куче с помощью указателя. И освобождать ее после того, как мы закончили работу с объектом. Реализуем это в нашей программе, немного изменив содержимое файла main.cpp.
/* main.cpp */<br>#include <iostream><br>#include "students.h"<br><br>int main()<br>{<br> // Выделение памяти для объекта Students<br> Students *student = new Students;<br><br> std::string name;<br> std::string last_name;<br><br> // Ввод имени с клавиатуры<br> std::cout << "Name: ";<br> getline(std::cin, name);<br><br> // Ввод фамилии<br> std::cout << "Last name: ";<br> getline(std::cin, last_name);<br><br> // Сохранение имени и фамилии в объект класса Students<br> student->set_name(name);<br> student->set_last_name(last_name);<br><br> // Оценки<br> int scores[5];<br> // Сумма всех оценок<br> int sum = 0;<br><br> // Ввод промежуточных оценок <br> for (int i = 0; i < 5; ++i) {<br> std::cout << "Score " << i+1 << ": ";<br> std::cin >> scores<em>;<br> // суммирование<br> sum += scores[i];<br> }<br> // Сохраняем промежуточные оценки в объект класса Student<br> student->set_scores(scores);<br><br> // Считаем средний балл<br> float average_ball = sum / 5.0;<br> // Сохраняем средний балл в объект класса Students<br> student->set_average_ball(average_ball);<br> // Выводим данные по студенту<br> std::cout << "Average ball for " << student->get_name() << " "<br> << student->get_last_name() << " is "<br> << student->get_average_ball() << std::endl;<br> // Удаление объекта student из памяти<br> delete student; <br> return 0;<br>}
При создании статического объекта, для доступа к его методам и свойствам, используют операция прямого обращения — «.» (символ точки). Если же память для объекта выделяется посредством указателя, то для доступа к его методам и свойствам используется оператор косвенного обращения — «[i]->».
Конструктор и деструктор класса
Конструктор класса — это специальная функция, которая автоматически вызывается сразу после создания объекта этого класса. Он не имеет типа возвращаемого значения и должен называться также, как класс, в котором он находится. По умолчанию, заполним двойками массив с промежуточными оценками студента.
class Students {<br> public:<br> // Конструктор класса Students<br> Students(int default_score)<br> {<br> for (int i = 0; i < 5; ++i) {<br> scores[i] = default_score;<br> }<br> }<br><br> private:<br> int scores[5];<br>};<br><br>int main()<br>{<br> // Передаем двойку в конструктор<br> Students *student = new Students(2);<br> return 0;<br>}
Мы можем исправить двойки, если ученик будет хорошо себя вести, и вовремя сдавать домашние задания. А на «нет» и суда нет 🙂
Деструктор класса вызывается при уничтожении объекта. Имя деструктора аналогично имени конструктора, только в начале ставится знак тильды ~. Деструктор не имеет входных параметров.
#include <iostream><br><br>class Students {<br> public:<br> // Деструктор<br> ~Students()<br> {<br> std::cout << "Memory has been cleaned. Good bye." << std::endl;<br> }<br>};<br><br>int main()<br>{<br> Students *student = new Students;<br> // Уничтожение объекта<br> delete student;<br> return 0;<br>}
Форум

Редакции сообщения
0
Stanislavovich
не в сети давно
На сайте с 19.12.2013
Участник
0
01:02

оххоххохохохохох выдал так выдал супер

Редакции сообщения
0
Tyr0I{
не в сети давно
На сайте с 09.03.2014
Участник
0
10:55

Спасибо! + выдал)

Редакции сообщения
0
igrok1908
не в сети давно
На сайте с 10.02.2015
Участник
0
23:41

Модификатор protected еще очень важен. Он более полезен, чем тот же private, когда речь идет о наследовании и есть необходимость получить доступ к полям родителя из класса-наследника.

Конструктор и деструктор в С++ играют большую роль, но очень важно знать, что есть такая разновидность конструктора, как конструктор копирования. Благодаря ему программа может передавать данные между сложными объектами, избегая так называемого "поверхностного" копирования...

А get и set-функции носят название аксессоров.... king Beer

Редакции сообщения
0
DmitryV
не в сети давно
На сайте с 04.06.2015
Участник
0
08:25

В этом уроке программы С++ компилируются под Linux Gentoo. Существуют ли отличия компиляция этих программ под Windows ?

Редакции сообщения
0

Ваше имя *

Ваш E-mail *

не публикуется

Текст сообщения *