Короткі теоретичні відомості. Клас - фундаментальне поняття С++, він лежить в основі багатьох властивостей С++
Клас.
Клас - фундаментальне поняття С++, він лежить в основі багатьох властивостей С++. Клас надає механізм для створення|створіння| об'єктів. У класі відбиті найважливіші концепції об'єктно-орієнтованого програмування: інкапсуляція, спадкоємство, поліморфізм.
З погляду синтаксису, клас в С++ - це структурований тип, утворений на основі вже існуючих типів.
У цьому сенсі|змісті,рації| клас є|з'являється,являється| розширенням поняття структури. У простому випадку клас можна визначити за допомогою конструкції:
тип_класса ім’я_класу{ список_членів_класу};
де тип_класу –одне з службових слів class, struct, union;
ім’я_класу – ідентифікатор;
список_членів_класу – визначення і описи даних, що типізуються, і функцій, що належать класу.
Функції – це методи класу, що визначають операції над об'єктом.
Дані – це поля об'єкту, що утворюють його структуру. Значення полів визначає стан об'єкту.
Приклади|зразки|.
struct date // дата
{int month,day,year; // поля: місяць, день, рік
void set(int,int,int); // метод – встановити дату
void get(int*,int*,int*); // метод – одержати|отримати| дату
void next(); // метод – встановити наступну|таку| дату
void print(); // метод – вивести дату
};
struct class complex // комплексне число
{double re,im;
double real(){return(re);}
double imag(){return(im);}
void set(double x,double у|в,біля|){re = x; im = у|в,біля|;}
void print(){cout<<“re = “<<re; cout<<“im = “<<im;}
};
Для опису об'єкту класу (екземпляра|примірника| класу) використовується конструкція
ім’я_класу ім’я_об’єкту;
date today,my_birthday;
date *point = &today; // покажчик на об'єкт типу date
date clim[30]; // масив об'єктів
date &name = my_birthday; // посилання|заслання| на об'єкт
В об'єкти, що визначаються, входять дані, відповідні членам - даним класу. Функції - члени класу дозволяють обробляти дані конкретних об'єктів класу. Звертатися|обертатися| до даних об'єкту і викликати|спричиняти| функції для об'єкту можна двома способами. Перший за допомогою “кваліфікованих” імен:
ім’я_об’єкту ім’я_даного
ім’я_объекту ім’я_ функції
Приклад:
complex x1,x2;
x1.re = 1.24;
x1.im = 2.3;
x2.set(5.1,1.7);
x1.print();
Другий спосіб доступу використовує покажчик на об'єкт
покажчик_ на об'єкт –>ім’я_компонента
complex *point = &x1; // або point = new complex;
point –>re = 1.24;
point –>im = 2.3;
point –>print();
Доступність компонентів класу.
У розглянутих|розгледіти| раніше прикладах|зразках| класів компоненти класів є|з'являються,являються| загальнодоступними. У будь-якому місці програми, де “видно|показно|” визначення класу, можна дістати доступ до компонентів об'єкту класу. Тим самим не виконується основний принцип абстракції даних – інкапсуляція (приховування|приховання|) даних усередині об'єкту. Для зміни видимості компонент у визначенні класу можна використовувати специфікатори доступу: public, private, protected.
Загальнодоступні (public) компоненти доступні в будь-якій частині|частці| програми. Вони можуть використовуватися будь-якою функцією як усередині даного класу, так і поза|зовні| ним. Доступ ззовні здійснюється через ім'я об'єкту:
ім’я_об’єкту. ім’я_члена_класу
посилання_на_об’єкт. ім’я_члена_класу
покажчик_на_об’єкт. ім’я_члена_класу
Приватні (private) компоненти локалізовані в класі і не доступні ззовні. Вони можуть використовуватися функціями – членами даного класу і функціями – “друзями” того класу, в якому вони описані.
Захищені (protected) компоненти доступні усередині класу і в похідних класах - нащадках.
Змінити|поміняти| статус доступу до компонентів класу можна і за допомогою використання у визначенні класу ключового|джерельного| слова class. В цьому випадку всі компоненти класу за умовчанням є|з'являються,являються| приватними
Приклад|зразок|.
class complex
{
double re, im; // private за умовчанням
public:
double real(){return re;}
double imag(){return im;}
void set(double x,double у|в,біля|){re = x; im = у|в,біля|;}
};
Конструктор.
Недоліком|нестачею| розглянутих|розгледіти| раніше класів є|з'являється,являється| відсутність автоматичної ініціалізації створюваних об'єктів. Для кожного новостворюваного об'єкту необхідно було викликати|спричинити| функцію типу set (як для класу complex) або явно присвоювати значення даним об'єкту. Проте|однак| для ініціалізації об'єктів класу в його визначення можна явно включити спеціальну компонентну функцію, звану конструктором. Формат визначення конструктора наступний|слідуючий|:
ім'я _класу(список_форм_параметрів){ оператори_тіла_конструктора}
Ім'я цієї компонентної функції за правилами мови|язика| С++ повинне співпадати|збігатися| з|із| ім'ям класу. Така функція автоматично викликається|спричиняється| при визначенні або розміщенні в пам'яті за допомогою оператора new кожного об'єкту класу.
Приклад|зразок|.
сomplex(double re1 = 0.0,double im1 = 0.0){re = re1; im = im1;}
Конструктор виділяє пам'ять для об'єкту і ініціалізує дані - члени класу.
Конструктор має ряд|лаву,низку| особливостей:
* Для конструктора не визначається тип значення, що повертається. Навіть тип void не припустимий.
* Покажчик на конструктор не може бути визначений, і відповідно не можна одержати|отримати| адресу конструктора.
* Конструктори не успадковуються|наслідують|.
* Конструктори не можуть бути описані з|із| ключовими|джерельними| словами virtual, static, const, mutuable, valatile.
Конструктор завжди існує для будь-якого класу, причому, якщо він не визначений явно, він створюється автоматично. За умовчанням створюється конструктор без параметрів і конструктор копіювання. Якщо конструктор описаний явно, то конструктор за умовчанням не створюється. За умовчанням конструктори створюються загальнодоступними (public).
Параметром конструктора не може бути його власний клас, але|та| може бути посилання|заслання| на нього (T&). Без явної вказівки програміста конструктор завжди автоматично викликається|спричиняється| при визначенні (створенні|створінні|) об'єкту. В цьому випадку викликається|спричиняється| конструктор без параметрів. Для явного виклику конструктора використовуються дві форми:
ім'я _класу ім'я _об’єкту (фактичні_параметри);
ім'я _класу (фактичні_параметри);
Перша форма допускається тільки|лише| при не порожньому|пустому| списку фактичних параметрів. Вона передбачає виклик конструктора при визначенні нового об'єкту даного класу:
complex ss (5.9,0.15);
Друга форма виклику приводить|призводить,наводить| до створення|створіння| об'єкту без імені:
complex ss = complex (5.9,0.15);
Існують два способи ініціалізації даних об'єкту за допомогою конструктора. Раніше ми розглядали|розглядували| перший спосіб, а саме передачу значень параметрів в тіло конструктора. Другий спосіб передбачає застосування|вживання| списку ініціалізаторів даного класу. Цей список розміщується| між списком параметрів і тілом конструктора. Кожен ініціалізатор| списку відноситься до конкретного компоненту і має вигляд|вид|:
ім’я_даного (вираз|вираження|)
Приклади|зразки|.
class CLASS_A
{
int i; float e; char з|із|;
public:
CLASS_A(int ii,float ее,char cc) : i(8),e( i * її + ii ),с(сс|){
. . .
};
Клас “символьний рядок”.
#include <string.h>
#include <iostream.h>
class string
{
char *ch; // покажчик на текстовий рядок
int len; // довжина текстового рядка
public:
// конструктори
// створює об'єкт – порожній|пустий| рядок
string(int N = 80): len(0){ch = new char[N+1]; ch[0]= ‘0’;}
// створює об'єкт по заданому рядку
string(const char *arch){len = strlen(arch);
ch = new char[len+1];
strcpy(ch,arch);}
// компоненти-функції
// повертає посилання|заслання| на довжину рядка
int& len_str(void){return len;}
// повертає покажчик на рядок
char *str(void){return ch;}
. . .};
Тут в|в,біля| класі string два конструктори – перенавантажувані|перевантажувані| функції.
За умовчанням створюється також конструктор копіювання вигляду|виду|
T::T(const T&),
де Т – ім'я класу. Конструктор копіювання викликається|спричиняється| всякий|усякий| раз, коли виконується копіювання об'єктів, що належать класу. Зокрема він викликається|спричиняється|:
а) коли об'єкт передається функції по значенню;
б) при побудові|шикуванні| тимчасового об'єкту який повертає функція;
в) при використанні об'єкту для ініціалізації іншого об'єкту.
Якщо клас не містить|утримує| явним чином певного конструктора копіювання, то при виникненні одній з цих трьох ситуацій проводиться|виробляється,справляється| побітове копіювання об'єкту. Побітове копіювання не у всіх випадках є|з'являється,являється| адекватним. Саме для таких випадків і необхідно визначити власний конструктор копіювання. Наприклад, в класі string:
string(const string& st)
{len=strlen(st.len);
ch=new char[len+1];
strcpy(ch,st.ch); }
Можна створювати масив об'єктів, проте|однак| при цьому відповідний клас повинен мати конструктор за умовчанням (без параметрів).
Масив об'єктів може ініціалізуватися або автоматично конструктором за умовчанням, або явним привласненням значень кожному елементу масиву.
class demo{
int x;
public:
demo(){x=0;}
demo(int i){x=i;}
};
void main(){
class demo а[20]; //виклик конструктора без параметрів(за умовчанням)
class demo b[2]={demo(10),demo(100)};//явне привласнення
Деструктори.
Динамічне виділення пам'яті для об'єкту створює необхідність звільнення|визволення| цієї пам'яті при знищенні об'єкту. Наприклад, якщо об'єкт формується як локальний усередині блоку, то доцільно, щоб при виході з|із| блоку, коли вже об'єкт перестає існувати, виділена для нього пам'ять була повернена. Бажано, щоб звільнення|визволення| пам'яті відбувалося|походило| автоматично. Таку можливість|спроможність| забезпечує спеціальний компонент класу – деструктор класу. Його формат:
~ім’я_класу(){ оператори_тіла_деструктора}
Ім'я деструктора співпадає|збігається| з|із| ім'ям його класу, але|та| передує символом “~” (тильда).
Деструктор не має параметрів і не повертає ніякого значення. Виклик
деструктора виконується неявно (автоматично), як тільки об'єкт класу знищується.
Наприклад, при виході за область визначення або при виклику оператора delete для покажчика на об'єкт:
string *p=new string (“рядок”);
delete p;
Якщо в класі деструктор не визначено явно, то компілятор генерує деструктор за умовчанням, який просто звільняє|визволяє| пам'ять, зайняту|позичену,посісти| даними об'єкту. У тих випадках, коли потрібно виконати звільнення|визволення| і інших об'єктів пам'яті, наприклад область, на яку указує|вказує| ch в об'єкті string, необхідно визначити деструктор явно: ~string(){delete []ch;}
Так само, як і для конструктора, не може бути визначений покажчик на деструктор.