Void Timer::Display (void)

{printf("year=%d month=%d day=%d hour=%d\

te=%d \n",p-->year,p-->month,p-->day,\

p-->hour,p-->minute);}

Схематично опис класу можемо задати так:

class<Ім’я_Класу>

{private:

<тип><ідентифікатор>;

..................

<тип><ідентифікатор>;

<тип><Ім’я_Функції11>(<сигнатура>);

...................

<тип><Ім’я_Функції1N1>(<сигнатура>);

protected:

<тип><ідентифікатор>;

...................

<тип><ідентифікатор>;

<тип результату><Ім’я_Функції21>(<сигнатура>);

...................

<тип результату> <Ім’я_Функції2N2>(<сигнатура>);

public:

<тип><ідентифікатор>;

...................

<тип><ідентифікатор>;

<тип результату><Ім’я_Функції31>(<сигнатура>);

...................

<тип результату><Ім’я_Функції3N3>(<сигнатура>);

<Ім’я_Класу>(<сигнатураА>);

<Ім’я_Класу>(<сигнатураБ>)

{<тіло функції>}

~ <Ім’я_Класу>(void);};

<тип результату><Ім’я_Класу>::<Ім’я_Функції11>(<сигнатура>)

{<тіло функції>}

<тип результату><Ім’я_Класу>::<Ім’я_Функції12>(<сигнатура>)

{<тіло функції>}

...........................

<тип результату><Ім’я_Класу>::<Ім’я_Функції3N3>(<сигнатура>)

{<тіло функції>}

<Ім’я_Класу>::<Ім’я_Класу>(<сигнатураА>)

{<тіло функції>}

<Ім’я_Класу>(<сигнатураБ>)

{<тіло функції>}

<Ім’я_Класу>:~<Ім’я_Класу>(void)

{<тіло функції>}

Усі програмні компоненти, що містяться між відкриваючою та закриваючою фігурними дужками опису класу "{" – "};", утворюють формальний опис класу. Під протоколом класу розумітимемо область, що складається з області формального опису класу й тіл функцій-членів, визначених за межами формального опису класу за допомогою операції розширення області видимості.

Бачимо, що формальний опис класу поділяється на три розділи, що задаються за допомогою ключових слів private, protected та public. Кожний розділ може містити поля даних і функції-члени. Порядок наступності розділів і їх кількість можуть бути довільними. Кількість полів у кожному розділі й порядок їх розміщення також можуть бути довільними. Якщо ключове слово відсутнє, то поля даних i функції-члени в цій частині опису класу вважаються закритими (для структур – відкритими).

Як видно зі схеми опису класу, крім звичайних функцій-членів класи можуть мати функції, імена яких збігаються з іменем класу або утворюються за схемою: ~ <Ім’я_Класу>. Це так звані конструктори та деструктори.

Конструктор – це функція-член, ім'я якої збігається з іменем класу. Він може мати порожній список параметрів. Допускаються параметри за умовчанням, перевантаження. Мета конструкторів – ініціалізація полів об'єкта (екземпляра класу). Присутність конструктора в протоколі класу необов'язкова.

Деструктор – це функція, ім'я якої ~ <Ім’я_Класу>. Деструктор повинен обов'язково мати порожнiй список параметрів. У класі може бути не більше одного деструктора. Мета деструктора – проведення коректних операцій при знищенні екземпляра класу (напр., звільнення пам'яті).

Конструктори й деструктори, так само як й інші функції-члени, можуть бути визначені за межами формального опису класу. Якщо визначення функції включається у формальний опис класу, то така функція розглядається компілятором як inline -функція. Діє правило: будь-яка змінна та функція доступна в межах протоколу класу. У межах протоколу класу можна вільно звертатись до будь-якої змінної чи функції, описаної в ньому (ніби вони перебувають в одному складеному операторі). Наприклад, у функції void Timer::Display (void) вільно використовуються поля month, hour та ін. без будь-яких додаткових описів. Коли визначено певний об'єкт – екземпляр класу, то прямий доступ ззовні протоколу можливий лише до полів даних і функцій-членів відкритого розділу (аналогічно тому, як це розглядалось для структур). Доступ до полів закритого й захищеного розділів здійснюється лише через функції-члени, що містяться у відкритих розділах.

Обмеженість доступу до полів даних класу має деякі переваги:

1) перший етап налагодження програми – локалізація помилки – виконується ще до запуску програми за рахунок її організації, адже помилка, пов'язана з використанням закритих даних, може виникнути лише у функції (описаній у відкритому розділі), що працює з цими даними;

2) для того, щоб працювати з об'єктами, користувач не обов'язково має знати структуру закритих даних. Достатньо лише знати функції, що працюють із цими даними;

3) легко можна змінювати закриту частину даних без змiни основної програми.

До специфіки захищеного розділу ми звернемося пізніше.

Для ілюстрації п. 2) розглянемо введення-виведення в С++. До системи С++ включаються класи ostream та istream. Виведення інформації здійснюється шляхом передавання об'єкту cout класу ostream повідомлення, яке виводиться. Наприклад, надрукувати рядок "a string" у С++ можна так:

cout<<"a string\n";

Об'єкту cout можуть передаватись множинні повідомлення:

int i;

cout<<"<<i<<"\n";

Допускається при цьому (у ранніх версіях) форматоване виведення за допомогою функцiї form, параметри якої аналогічні параметрам функції printf:

cout<<form("i=%d",i);

Для введення потрібно здійснити передавання об'єкту cin класу istream повідомлення зі змінною, яка приймає дані, що вводяться, як параметр. Аналогічно здійснюється форматоване введення:

cin>>form("i=%d",&i);

Система введення–виведення С++ дуже складна. Класи введення–виведення утворюють складну ієрархію, кожен клас має свої функції та поля даних. Проте користувач може взагалі не знати всієї внутрішньої організації. Достатньо знати лише, яким об'єктам і як передаються відповідні повідомлення. Навіть за кількома наведеними вище прикладами і стислою інформацією ми формально можемо навчитись вводити та виводити дані в С++ (у найпростіших випадках). При цьому поки що для нас залишається незрозумілим, як і чому саме так усе відбувається на внутрішньому рівні.

Синтаксично визначення об'єкта (екземпляра класу) у найпростішому випадку нічим не відрізняється від визначення елемента типу struct:

Class ClassName

{

public:

int p;};

ClassName object;

Можемо визначити покажчик на клас ClassName:

ClassName*objectPointer;

Очевидно, що й доступ до відкритих полів екземпляра класу буде синтаксично реалізований аналогічно, як і для структур, за допомогою операцій "." та "->":

cout<<ClassName.p;

objectPointer=new ClassName;

cout<<objectPointer->p;

За концепцією ООП, доступ до полів об'єкта означає передавання йому деякого повідомлення. Наприклад, у випадку класу Тime, звертаючись до функції Display, ми ніби запитуємо, котра година, тобто повідомляємо об'єкту про наш запит, передаємо йому повідомлення.

Під повідомленням формально будемо розуміти програмну конструкцію звертання до поля об'єкта. Якщо звертаємось до поля-функції, то повідомлення схематично можемо зобразити так:


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: