Классы в C++: руководство для начинающих!
Всем привет! Объекты очень важная вещь в программировании, которая может облегчить решения многих задач. Например нужно вести дневник пользователя: год рождения, имя, фамилия, местожительство, все это можно продолжать еще очень долго. Поэтому, как и другие языки программирования C++ обзавелся — классами.
- Что такое класс
- ООП в программировании
- Доступы public и private
- Карточка работника
- Массив объектов
- Отделение методов от логики
- Инициализация объектов с помощью указателей
- Конструктор и деструктор
Как создать класс
Чтобы объявить класс нужно использовать данную конструкцию:
1 2 3 |
class <имя класса> { }; |
Обычно <имя класса>
прописывают с заглавной буквы. Также в конце обязательно должна присутствовать точка с запятой (;
).
Что такое класс
Это абстрактный тип данных. Он сочетает в себе два функционала:
- Первая — это структура, в которой можно хранить различные типы данных: массивы, переменные, функции.
- Вторая — возможность пользоваться объектно-ориентированным программированием (ООП — об этом ниже).
Создав класс можно создать его экземпляр — объект. Объект — это функционирующий прототип класса, которому можно задавать свойства и вызывать методы.
У каждого вами созданного класса могут быть свойства и методы. Свойства — это все что может хранить информацию, которую вы потом можете заполнять (переменные, массивы и т.д.).
Так свойства класса Worker
(рабочий) может иметь — имя, производительность (полезность работы) за 6 месяцев, среднюю производительность.
1 2 3 4 5 6 7 8 |
class Worker { public: // об этом ниже string name; // имя // производительность в течении 6 месяцев int academic_performance[6]; // средняя производительность int avarage_AP; }; |
Методы — это обычные функции, в функционале которых можно использовать свойства.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class Worker { public: // об этом ниже // функция для вычисления средней производительности void discover_avarage_AP () { double answer = 0; for (int i = 0; i < 6; i++) { answer += academic_performance[i]; } avarage_AP = answer / 6; // вычисляем с.п. } string name; // имя // производительность в течении 6 месяцев int academic_performance[6]; // средняя успеваемость int avarage_AP; }; |
Чтобы обратится к свойствам и методам класса нужно перед названием имени свойства поставить точку .
.
1 |
<имя класса>.<название свойства или метода>; |
Что такое ООП
Раньше программистам приходилось весь функционал программы записывать в одном файле. Что в будущем неизбежно приводило к путанице из-за нескольких сотен и даже тысяч строк. А с приходом классов появилась возможность отделять любую часть программы в отдельный файл.
Например один файл отвечает за инициализацию введенных данных, другой за считывание производительности. Таким образом стала возможным структурировать программу.
В ООП входит такие свойства:
- Инкапсуляция — это возможность задавать разную область видимости определенной части класса .
- Наследование — это свойство создавать новый класс на базе старого. Такие классы называют потомками, например, есть класс
магазин
, на базе которого можно создать потомкипродуктовый_магазин
,магазин_одежды
(не обращайте внимание, что название на русском языке). - Полиморфизм — возможность создать объекты с одинаковым интерфейсом, но с разной их реализацией. Например, есть три класса
треугольник
,круг
иквадрат
. У каждого из них есть методSquarePlis()
, который вычисляет площадь фигуры. Но для каждого класса функция реализована по-разному.
123456789SquarePlis() {square = a * a; // для квадратаsquare = 1 / 2 * h * a; // для треугольникаsquare = 3.14 * r * r; // для круга} - Абстракция — это возможность выбирать только те свойства или функции, которые нам необходимы. Например, при создании класса про работника понадобится указать его имя, возраст, образование, но никак его цвет волос, глаз, рост и тому подобное.
Спецификаторы доступа public и private
Для разграничение содержимого класса, например которое пользователю лучше не трогать, были добавлены спецификаторы доступа public, private и protected (о нем пойдет речь в следующем уроке про наследование). Это и есть инкапсуляция, которую мы упоминали выше.
public
— дает публичный доступ, содержимому, которое в нем указано. Так можно обратится к любой переменной или функции из любой части программы.private
— запрещает обращаться к свойствам вне класса. Поэтому под крылом этого доступа часто находятся именно объявления переменных, массивов, а также прототипов функций.Оперировать его содержимым можно только из методов класса. Получается все преобразования: добавление, вычитание нужно будет делать в функции (их еще называют set и get функциями).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
class Worker { public: void discover_avarage_AP () { // ... set_avarage_AP(answer); // вместо avarage_AP = answer / 6; } void set_avarage_AP (double score) { avarage_AP = score / 6; } double get_avarage_AP () { return avarage_AP; } private: string name; // имя // успеваемость за 6 месяцев int academic_performance[6]; // средняя успеваемость int avarage_AP; }; |
- В строке 5: используем функцию
set_avarage_AP()
для установки нового значенияavarage_AP
. - В строке 13: находится функция
get_avarage_AP()
, которая передает значенияavarage_AP
.
Если отсутствуют права доступа, то по умолчанию будет стоять доступ
private
.
Размещать права доступа можно в разном порядке, но лучше сделать свою систему которой вы будете придерживаться в будущих проектах.
Функции get и set классов
При создании класса обычно создают функции в названии которых присутствуют слова set
и get
.
set
— в ней инициализируют свойства класса.
12345set_number() { // set и имя переменнойcin >> number; // которую инициализируют}private:int number; // наша переменнаяget
— выводит свойства конечному пользователю.
12345get_number() { // get и переменнаяreturn number; // которую возвращают}private:int number; // наша переменная
Пример использования классов
Давайте используем созданный класс на практике создав карточку об одном работнике, например Иване. Класс разместим в файле workers.h
, который подключим к главному файлу main.cpp
таким образом #include "workers.h"
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
// workers.h #include <string> using namespace std; class Worker { public: void discover_avarage_AP () { double answer = 0; for (int i = 0; i < 6; i++) { answer += academic_performance[i]; } set_avarage_AP(answer); // вместо avarage_AP = answer / 6; } void set_avarage_AP (double score) { avarage_AP = score / 6; } // здесь находятся set и get функции double get_avarage_AP () { return avarage_AP; } void set_name(string a) { // считываем имя name = a; } void set_academic_performance (vector v) { // заполняем 6 месячныю успеваемость for (int i = 0; i < 6; i++) { academic_performance[i] = v[i]; } } string get_name () { // выводим имя return name; } // конец set и get функций private: // средняя успеваемость int avarage_AP; string name; // имя // успеваемость за 6 месяцев int academic_performance[6]; }; |
В строках 19-34: находятся set
и get
функции для инициализации наших свойств. Вот какие именно:
get_name()
— считывает имя работника.get_academic_perfomence()
— считывает успеваемость на работе за шесть месяцев.
Функции set имеют такое же название, только вместо get — set.
А вот как выглядит main.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
// main.cpp #include <iostream> #include <vector> #include "workers.h" using namespace std; int main() { Worker employee; string name; vector <int> average_balls; cout << "Your name: "; cin >> name; cout << "Your academic performance for 6 months: " << endl; for (int i = 0; i < 6; i++) { int one_score; cout << i + 1 << ") "; cin >> one_score; average_balls.push_back(one_score); } employee.set_name(name); employee.set_academic_performance(average_balls); employee.discover_avarage_AP(); cout << endl << employee.get_name() << endl; cout << "Avarage academic performance: " << employee.get_avarage_AP() << endl; return 0; } |
Для создания объекта employee
мы указали класс Worker
.
- В строках 14 — 21: считываем пользовательские данные.
- В строках 23- 24: отсылаем полученные данные классу (функциями set).
- Вычисляем среднюю успеваемость вызвав функцию
discover_avarage_AP()
в строке 26. - В строках 28 — 29: выводим все свойства: имя, фамилию, возраст, средний балл.
employee
это журнал всего лишь для одного работника, если нам потребуется вести такие журналы всей компании, то придется создать для каждого человека свой объект.
Как создать массив объектов
Кроме создания единичного объекта класса можно создать целый массив объектов. Нужно всего лишь в конец создаваемого объекта добавить его количество ([n]
).
1 2 3 4 5 |
Worker employee[5]; cout << "Name for second employee : "; cin >> name; employee[2].set_name(name); |
Здесь мы просим пользователя ввести имя для второго работника. Далее вводим введенное имя в объект employee[2]
с помощью функции set_name()
.
Вынесение методов от логики
Давайте отделим реализацию всех методов отдельный файл.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
// main.cpp #include <iostream> #include "Worker.h" void Worker::discover_avarage_AP () { double answer = 0; for (int i = 0; i < 6; i++) { answer += academic_performance[i]; } set_avarage_AP(answer); } void Worker::set_avarage_AP (double score) { avarage_AP = score / 6; } // set - get функции double Worker::get_avarage_AP () { return avarage_AP; } void Worker::set_name(string a) { // считываем имя name = a; } void Worker::set_academic_performance (vector v) { // заполняем 6 месячныю успеваемость for (int i = 0; i < 6; i++) { academic_performance[i] = v[i]; } } string Worker::get_name () { // выводим имя return name; } |
А вот файл с логикой класса.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
class Worker { public: // высчитывание среднего балла void discover_avarage_AP (); void set_avarage_AP (double score); // вывод средней успеваемости double get_avarage_AP (); // получение и вывод имени void set_name(string a); string get_name (); // получение баллов за шесть месяцев void set_academic_performance (vector v); private: // средняя успеваемость int avarage_AP; string name; // имя // успеваемость за 6 месяцев int academic_performance[6]; }; |
Только что мы применили один из фундаментальных принципов объектно ориентированного программирования — абстракция данных. Если ваш класс будут применять в своих целях, им не нужно знать, как реализована какая-то в нем функция. Например, можно для вычисления средней успеваемости применить функцию discover_avarage_AP()
, и даже не вдаваться в ее принцип работы.
В одной из прошлых статей мы разбирали работу пространства имен — namespace. Когда работают несколько программистов над проектом часто случается, что один программист не знает, что уже создан класс или функция с таким именем. Именно в таких случаях помогает префикс ::
который сигнализирует, что эта функция или переменная принадлежит именно к этому классу.
Поэтому перед каждой функцией стоит данный префикс.
Инициализация объектов с помощью указателей
Когда обычным образом создаем объект мы копируем память компьютера, что не есть хорошо. Поэтому лучше выделять память в куче с помощью указателя. Если уж быть вообще правильным то в конце программы нужно удалять каждый созданный объект.
Чтобы создать объект с помощью указателя необходимо использовать конструкцию ниже:
1 |
<название класса> *<имя объекта> = new <название класса> |
Для освобождения памяти используется оператор delete
:
1 |
delete <название объекта>; |
При обращении к свойствам и методам объекта применяется такая конструкция (->
):
1 |
<имя объекта>-><название свойства или метода> |
Давайте используем данную реализацию в нашей программе.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
// main.cpp #include <iostream> #include <vector> #include workers.h using namespace std; int main() { Worker *employee = new Worker; string name; vector <int> average_balls; cout << "Your name: "; cin >> name; cout << "Your academic performance for 6 months: " << endl; for (int i = 0; i < 6; i++) { int one_score; cout << i + 1 << ") "; cin >> one_score; average_balls.push_back(one_score); } employee->set_name(name); employee->set_academic_performance(average_balls); employee->discover_avarage_AP(); cout << endl << employee->get_name() << endl; cout << "Avarage academic performance: " << employee->get_avarage_AP() ; return 0; } |
Конструктор и деструктор класса
Конструктор — это метод, который вызывается во время создания класса. Также он имеет несколько условий для существования:
- Он должен называться также, как класс.
- У него не должно быть типа функции (bool, void …).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
class Worker { public: // Конструктор для класса Worker Worker (string my_name_is, string my_last_name_is) { name = string my_name_is; last_name = my_last_name_is; } private: string name; string last_name; }; int main() { Worker employee ("Ваня", "Шарапов"); // вот как будет выглядеть, если мы создаем через указатель Worker *employee_CocaCola = new Worker("Дмитрий","Талтонов"); return 0; } |
Деструктор — тоже функция, только уже вызывается после удаления класса. Кроме условий, которые имеет конструктор, деструктор еще должен начинаться с тильды (~).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
class Workers { public: // Деструктор класса Workers ~Workers() { std::cout << "I'm sorry, my creator(" << std::endl; } }; int main() { Workers *employee = new Workers; Worker employee_CocaCola; // Удаление объекта delete student; // после этого сработает деструктор employee return 0; } // А вот где сработает деструктор employee_CocaCola |
Классы в C++
Если эта надпись не исчезает долгое время, попробуйте обновить страницу. Этот тест использует javascript. Пожалуйста, влкючите javascript в вашем браузере.
В разделе «Что такое класс», плз, исправьте аббревиатуру ОПП на ООП.
«Вторая — возможность пользоваться объектно-ориентированным программированием (ОПП — об этом ниже).»
Спасибо!
Конструктор вызывается во время создания класса, а не после
Спасибо, исправили!
В файле workers.h в 26 строке объявление массива (vector v) -> (vector v)
в этом же файле стоит указать
«using namespace std;» (без кавычек)
перед созданием класса, перед строкой class Worker {
Ибо множество синтаксических ошибок повыскакивает
Спасибо, исправил