Клас являє собою абстрактний тип даних, що визначається користувачем і являє собою модель реального об’єкта у вигляді даних та функцій для роботи з ними.
Оголошення класу має таку форму:
class сім’я класу> : список класів-батьків>
{
public: // доступно всем
<дані, методи, властивості, події>
protected: // доступно только потомкам
<дані, методи, властивості, події>
private: // доступно только в классе
<дані, методи, властивості, події>
} <список змінних>
Об’єкт — це змінна типу клас. Дані класу називаються полями, а функції —методами, що призначені для обробки полів. Крім методів, тип клас може мати спеціальні функції — конструктори і деструктори.
Однією з найцікавіших властивостей об’єктно-орієнтованого програмування (ООП) є можливість успадкування даних і функцій. У випадку, коли один клас успадковує інший, базовий клас називають батьківським, а той, що успадковує, — похідним або нащадком.
Розміщення описів змінних і функції з їх обробки, тобто полів та методів в одному класі називається інкапсуляцією.
Класи в С++ мають три різних рівні доступу до своїх елементів, тобто даних (полів) і функцій (методів):
- закриті елементи (private);
- захищені елементи (protected);
- відкриті елементи (public).
До даних у закритому розділі (private) мають доступ тільки функції-елементи свого класу. Класам-нащадкам забороняється доступ до закритих даних своїх базових (батьківських) класів. За замовчуванням усі дані-члени класу мають атрибут private(закритий).
До даних у захищеному розділі (protected) мають доступ функції свого класу і функції класів-нащадків.
У свою чергу до даних відкритого розділу (public) можуть звертатися будь-які функції.
Існують такі правила створення розділів класу:
- розділи можуть з’являтися в будь-якому порядку і декілька разів;
- якщо не оголошено жодного розділу, компілятор за замовчуванням оголошує усі елементи закритими;
- розміщати дані-елементи класу у відкритому розділі можна тільки за необхідності. Дані-елементи класу звичайно розміщують у закритому, або захищеному розділі, щоб до них мали доступ функції-члени класу, а також функції класів-нащадків;
- для зміни значень даних (полів) слід використовувати функції-члени класу;
- клас може мати декілька конструкторів, але тільки один деструктор.
Розглянемо приклад використання класу.
Приклад 11.1. Навести просту програму з використанням класу.
// P11_1.CPP — использование класса, структура класса #include <iostream.h> #include <conio.h> class myclass { int p; // закрытая переменная no умолчанию public: void set_p(int x); // прототипы функций-членов класса int get_p(); }; //------------------------- описание функций-членов класса void myclass::set_p(int x) { p = x; } int myclass::get_p( ) { return p; } main() { myclass ob1, ob2; // объявление объектов // вызов функций-членов класса ob1.set_p(10); ob2.set_p(30); cout<<"p1= "<<ob1.get_p()<<" "; cout<<"p2= "<<ob2.get_p()<<endl; getch (); return 0; }
Результати обчислень:
p1= 10
p2= 30
У програмі оголошено клас з ім’ям myclass, що має одну закриту змінну р і дві відкриті функції-члени класу set_p() і get_p(). Перша з функцій призначена для ініціювання закритої змінної р, а друга — для її повернення.
В описі класу оголошено тільки прототипи функцій, їх реалізацію наведено за межами опису. Але якщо функція складається з декількох операторів, її можна розмістити всередині класу. Оскільки ці функції є членами класу, то вони мають доступ до закритої змінної р.
У випадку, коли функції-члени описано за межами класу, їхні заголовки повинні складатися з імені класу, операції розширення області класу «::», імені функції та її формальних аргументів, якщо вони є, а далі йтиме зміст функції.
У головній функції main() спочатку оголошуються два об’єкти типу myclass, потім ці об’єкти ініціюються конкретними значеннями змінної р (ob1.set_p(10) та ob2.set_p(30),після цього значення цієї змінної виводяться на екран (cont<<ob1.get_p(); таcout<<ob2.get_p0).
Треба звернути увагу, що елементи класу записуються через крапку після імені об’єкта.
Серед функцій-членів класу можуть бути такі, що визначають процеси створення, ініціювання, копіювання та знищення об’єктів свого класу. До цих функцій належать конструктори і деструктори, які у попередній програмі не використовувались (у такому випадку вони автоматично викликликалися системою за замовчуванням), тому в оголошенні об’єктів ob1 та оb2 не було параметрів їхнього ініціювання, для цього використовувалась функція set_p().
Головною метою конструкторів є ініціювання змінних-об’єктів класу та розподілення пам’яті для їх зберігання. Конструктор викликається кожного разу при створенні об’єкта даного класу або явно, або автоматично (див. Р11_1.СРР).
Основні правила роботи з конструкторами:
- ім’я конструктора повинне співпадати з ім’ям свого класу;
- для конструктора не вказується тип значення, яке повертає функція;
- клас може мати декілька конструкторів або не мати жодного;
- конструктор за замовчуванням — це конструктор, який не має параметрів, або всі його параметри мають значення за замовчуванням;
- конструктор копіювання безпосередньо призначений для створення об’єкта класу шляхом копіювання даних з існуючого об’єкта.
Наведемо приклади оголошення конструкторів:
Class cls1 {
int х, у; // защищенные переменные класса
public:
cls1(); // конструктор по умолчанию без параметров
cls1 (int xval=0; int yval=0); /* конструктор no умолчанию с параметрами, имеющими значения по умолчанию */
cls1(const clsl &pt); // конструктор копирования
};
При оголошенні об’єкти ініціюють захищені змінні, тому вони оголошуються з параметрами або без них залежно від виду конструктора. Якщо клас має декілька конструкторів, для кожного об’єкта використовується той, що співпадає з ним за кількістю та типом аргументів.
Якщо в головній програмі оголошено, наприклад:
main() {
cls1 p1; cls1 p2(10,20); cls1 р3(р2);
}……………………………
то у першому випадку буде виконуватися конструктор за замовчуванням без параметрів, у другому — конструктор з параметрами за замовчуванням, у третьому — конструктор копіювання.
Деструктори необхідні для автоматичного руйнування об’єктів класу. їх використання має такі особливості:
- ім’я деструктора повинно починатися знаком ~ (тильда), за яким записується ім’я класу;
- для деструктора не вказується тип значення, що повертається (як і для конструкторів);
- клас завжди має тільки один деструктор або не має жодного. У такому випадку компілятор сам створює деструктор за замовчуванням;
- деструктор не може мати параметрів; програма автоматично викликає деструктор, якщо об’єкт класу виходить за межі області дії і повинен бути знищений.
Приклад 11.2. Навести програму, в якій конструктор використовується для ініціювання закритої змінної х, а деструктор — для її руйнування.
// Р11_2. СРР — использование конструкторов и деструкторов #include <iostream.h>
class myclass2
Конструктори і деструктори необхідні для роботи з динамічними даними. Для виділення динамічної пам’яті користуються оператором new у конструкторі, а для її звільнення — оператором delete у деструкторі.
Розглянемо програму, в якій за допомогою конструктора виділяється динамічна пам’ять для рядка символів, ініціюється закрита змінна len, а деструктор звільняє цю пам’ять після її використання.
Приклад 11.3. Навести програму, в якій треба ввести рядок символів, потім вивести на екран цей рядок і кількість символів у ньому.
/* Р11_З.СРР — использование конструкторов и деструкторов при работе с динамическими данными */
#include <iostream.h>
#include <string.h>
#include <conio.h>
class strclass {
char *str;
int len;
public:
strclass(int size) //—————————- конструктор класса
{
str=new char[size]; //выделение динамич. памяти для строки
len=size;
}
~ strclass( ) //———————————–деструктор класса
{
delete str; // освобождение динамической памяти
}
//——————————— прототипы фукщй ввода и вывода
int input(void);
void output(void);
};
//—————————————— функция ввода строки
int strclass::input(void)
{
сout<<“Enter stroky not large “<<len<<” symbols\n”;
cin.getline(str, len);
return strlen(str);
}
/——————————————- функция вывода строки
void strclass::output(void) {
cout << str << ‘\n’;
}
void main() {
int lenght;
strclass my(100); // объявление объекта класса
lenght = my.input( );
cout << “Stroka= ” << lenght << ” symbols\n”;
my.output( );
getch ();
Результат розв’язання програми:
Enter stroky not large 100 symbols
Существуют правила создания разделов класса
Stroka= 43 symbols
Существуют правила создания разделов класса
При успадкуванні, за необхідності, можна перевизначити деякі функції батьківського класу в класі-нащадку.
Звичайно у базовому класі описуються найбільш загальні властивості, які придатні для всіх похідних від нього класів. Похідний клас успадковує ці загальні властивості і додає нові, характерні тільки для нього.
Загальна форма оголошення похідного класу має вигляд:
ік : [специфікатор доступу] ім’я базового класу { };,
де ік — ім’я оголошеного класу, а у фігурних дужках записується зміст цього класу.
Приклад 11.4. Розробити програму, що реалізує приклад взаємодії базового (class А) і похідного (class В) класів.
// Р11_4.СРР — взаимодействие базового и производного классов #include <iostream.h> #include <conio.h> class A //----------- базовый класс { int і; public: void set_i(int n) { і = n; } int get_i() { return i; } }; class B: public A //----------- производный класс { int j; public: void set_j(int n) { j = n; } int mult() { return j*get_i(); } }; main() { В ob; ob.set_i(10); ob.set_j(4); cout<<"Rezultat= "<<ob.mult()<<endl; getch (); return 0; }
Результат роботи програми:
Rezultat= 40
У програмі подано спочатку опис базового класу А, а потім похідного класу В. У похідному класі оголошено, що базовий клас є відкритим для похідного, тобто всі захищені і відкриті дані і функції (але не закриті) класу А доступні в класі В. За таких умов у функції mult() використовується відкрита функція get_i() класу А, однак змінна і, яка оголошена в закритому розділі класу А, безпосередньо не може застосовуватися у класі В.
У головній програмі оголошено об’єкт ob класу В, однак для його обробки реалізується як функція ob.set_i(10) класу А, так і функція ob.set_j(4) класу В. Тому при виконанні функції ob.mult() буде виведено 40. Якби клас А успадковувався у закритому (private)режимі, то усі його елементи було б заборонено використовувати в класі-нащадку.