Классы в C++: руководство для начинающих!
 
        Всем привет! Объекты очень важная вещь в программировании, которая может облегчить решения многих задач. Например нужно вести дневник пользователя: год рождения, имя, фамилия, местожительство, все это можно продолжать еще очень долго. Поэтому, как и другие языки программирования C++ обзавелся - классами.
Как создать класс
Чтобы объявить класс нужно использовать данную конструкцию:
class <имя класса> {
};Обычно <имя класса> прописывают с заглавной буквы. Также в конце обязательно должна присутствовать точка с запятой (;).
Что такое класс
Это абстрактный тип данных. Он сочетает в себе два функционала:
- Первая - это структура, в которой можно хранить различные типы данных: массивы, переменные, функции.
- Вторая - возможность пользоваться объектно-ориентированным программированием (ООП - об этом ниже).
Создав класс можно создать его экземпляр - объект. Объект - это функционирующий прототип класса, которому можно задавать свойства и вызывать методы.
 
        У каждого вами созданного класса могут быть свойства и методы. Свойства - это все что может хранить информацию, которую вы потом можете заполнять (переменные, массивы и т.д.).
Так свойства класса Worker (рабочий) может иметь - имя, производительность (полезность работы) за 6 месяцев, среднюю производительность.
class Worker {
  public:  // об этом ниже
    string name; // имя
    // производительность в течении 6 месяцев
    int academic_performance[6];
    // средняя производительность
    int avarage_AP;
};Методы - это обычные функции, в функционале которых можно использовать свойства.
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;
};Чтобы обратится к свойствам и методам класса нужно перед названием имени свойства поставить точку ..
<имя класса>.<название свойства или метода>;Что такое ООП
Раньше программистам приходилось весь функционал программы записывать в одном файле. Что в будущем неизбежно приводило к путанице из-за нескольких сотен и даже тысяч строк. А с приходом классов появилась возможность отделять любую часть программы в отдельный файл.
Например один файл отвечает за инициализацию введенных данных, друг ой за считывание производительности. Таким образом стала возможным структурировать программу.
В ООП входит такие свойства:
- 
Инкапсуляция - это возможность задавать разную область видимости определенной части класса . 
- 
Наследование - это свойство создавать новый класс на базе старого. Такие классы называют потомками, например, есть класс магазин, на базе которого можно создать потомкипродуктовый_магазин,магазин_одежды(не обращайте внимание, что название на русском языке).
- 
Полиморфизм - возможность создать объекты с одинаковым интерфейсом, но с разной их реализацией. Например, есть три класса треугольник,кругиквадрат. У каждого из них есть методSquarePlis(), который вычисляет площадь фигуры. Но для каждого класса функция реализована по-разному.SquarePlis() { square = a * a; // для квадрата square = 1 / 2 * h * a; // для треугольника square = 3.14 * r * r; // для круга }
- 
Абстракция - это возможность выбирать только те свойства или функции, которые нам необходимы. Например, при создании класса про работника понадобится указать его имя, возраст, образование, но никак его цвет волос, глаз, рост и тому подобное. 
Спецификаторы доступа public и private
Для разграничение содержимого класса, например которое пользователю лучше не трогать, были добавлены спецификаторы доступа public, private и protected (о нем пойдет речь в следующем уроке про наследование). Это и есть инкапсуляция, которую мы упоминали выше.
- 
public- дает публичный доступ, содержимому, которое в нем указано. Так можно обратится к любой переменной или функции из любой части программы.
- 
private- запрещает обращаться к свойствам вне класса. Поэтому под крылом этого доступа часто находятся именно объявления переменных, массивов, а также прототипов функций.Оперировать его содержимым можно только из методов класса. Получается все преобразования: добавление, вычитание нужно будет делать в функции (их еще называют set и get функциями).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- в ней инициализируют свойства класса.set_number() { // set и имя переменной cin >> number; // которую инициализируют } private: int number; // наша переменная
- 
get- выводит свойства конечному пользователю.get_number() { // get и переменная return number; // которую возвращают } private: int number; // наша переменная
Пример использования классов
Давайте используем созданный класс на практике создав карточку об одном работнике, например Иване. Класс разместим в файле workers.h, который подключим к главному файлу main.cpp таким образом #include "workers.h".
// 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
// 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 это журнал всего лишь для одного работника, если нам потребуется вести такие журналы всей компании, то придется создать для каждого человека свой объект.
Your name: Иван
Your academic performance for 6 months:
1) 3
2) 4
3) 5
4) 5
5) 3
6) 4
Иван
Avarage academic performance: 4
Process returned 0 (0x0) execution time : 0.010 s
Press any key to continue.Как создать массив объектов
Кроме создания единичного объекта класса можно создать целый массив объектов. Нужно всего лишь в конец создаваемого объекта добавить его количество ([n]).
Worker employee[5];
cout << "Name for second employee : "; cin >> name;
employee[2].set_name(name);Здесь мы просим пользователя ввести имя для второго работника. Далее вводим введенное имя в объект employee[2] с помощью функции set_name().
Вынесение методов от логики
Давайте отделим реализацию всех методов отдельный файл.
// 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;
}А вот файл с логикой класса.
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. Когда работают несколько программистов над проектом часто случается, что один программист не знает, что уже создан класс или функция с таким именем. Именно в таких случаях помогает префикс :: который сигнализирует, что эта функция или переменная принадлежит именно к этому классу.
Поэтому перед каждой функцией стоит данный префикс.
Инициализация объектов с помощью указателей
Когда обычным образом создаем объект мы копируем память компьютера, что не есть хорошо. Поэтому лучше выделять память в куче с помощью указателя. Если уж быть вообще правильным то в конце программы нужно удалять каждый созданный объект.
Чтобы создать объект с помощью указателя необходимо использовать конструкцию ниже:
<название класса> *<имя объекта> = new <название класса>Для освобождения памяти используется оператор delete:
delete <название объекта>;При обращении к свойствам и методам объекта применяется такая конструкция (->):
<имя объекта>-><название свойства или метода>Давайте используем данную реализацию в нашей программе.
// 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 …).
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;
}Деструктор - тоже функция, только уже вызывается после удаления класса. Кроме условий, которые имеет конструктор, деструктор еще должен начинаться с тильды (~).
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Если хотите всегда быть в курсе последних новостей в мире программирования и IT, подписываетесь на мой Telegram-канал, где я делюсь свежими статьями, новостями и полезными советами. Буду рад видеть вас среди подписчиков!
Обсуждение