Cтатичні члени класів і статичні класні функції
Доповнимо клас Employee визначенням вільного ідентифікаційного коду службовця. Самий простий спосіб — оголосити його статичною змінною:
static unsigned int currentId;
інкапсулювавши її клас, для чого її оголошення розміщується в його інтерфейсі. Як ми пам'ятаємо, атрибути ініціалізуються особливо. Звичайні атрибути — при створенні об'єкта. Статичний атрибут спільний для всіх об'єктів класу, а тому ідентифікується без посилання на об'єкт і створюється компонувальником за його визначенням, яке розміщується у файлі реалізації
unsigned int Employee :: currentId = 0;
Відповідних змін може зазнати конструктор, в якому тепер стане на параметр менше. Залежно від обставин ним може виявитися додатково довизначений конструктор
16. Основи перевантаження операторів. Перевантаження бінарного оператора . (+)..Правила перевантаження операторів. Навести приклади.
Оператори С++ представляють собою альтернативний запис виклику функцій асоційованих з математичними та логічними функціями. Вони вбудовані в мову і використовуються для певних дій (операцій) з вбудованими типами.
Подібність між операторами та викликами функцій дозволяє створення користувацьких (перевантажених) операторів, які будуть коректно працювати з різними типами об’єктів, які є екземплярами користувацьких класів. Це дає можливість створювати самодостатні програмні конструкції із своїм набором дій, який уніфікований за викликами із стандартним набором.
Перевантаження операторів задумане з метою спрощення запису та уніфікації виразів. Більше того, перевантажені оператори можуть наслідуватись. Власне поширення концепції перевантаження операторів еквівалентне звертанню до функцій і є новим в С++.
Відомо оператори, як функції, можуть співставлятись з об’єктами двома методами: як функції-члени і як друзі (чи звичайні сторонні функції). Так, наприклад, застосування унарного операції ~ (інверсія бітів) до об’єкта ~W, може бути записано у двох формах виклику функції operator~():
W.operator~(); // як функція-член
operator~(W); // як дружня (чи просто стороння) функція
Бінарні оператори можна записати подібно. Наприклад, операція додавання + по відношенню до двох об’єктів X та Y (тобто X+Y) еквівалентна викликам:
X.operator+(Y); // як функція-член
operator+(X,Y); // як дружня (чи просто стороння) функція
Виклик X.operator+(Y) передбачає, що функція operator+()є методом об’єкта X тобто першого операнда. Це означає, що в цьому випадку оператори не комутативні, оскільки операнд X може бути екземпляром зовсім іншого типу, а оператор Y.operator+(X) в даному випадку не розглядається.
З прикладів видно, що оператори можуть використовують дві різні функції, які, в загальному випадку, можуть зреалізовувати зовсім різні дії. У випадку, коли компілятору доступні обидві версії, починає працювати механізм визначення сумісності типів. Якщо правилу сумісності відповідають обидві функції, то генерується помилка.
Зауважим, що випадку n-арного оператора як дружньої випадку, функція оператор приймає n аргументів. У випадку методі класу - (n-1) аргумент. Тобто, арність оператора однозначно визначає кільіксть параметрів при перевантаженні оператора. Наприклад унарний оператор у випадку методу класу однозначно не приймає жодних аргументів.
Необхідно пам’ятати про обмеження, які супроводжують використання перевантажених операторів
1. Перевантажені функції не можуть змінити пріорітет операторів.
2. Кількість операндів є фіксованим.
3. Значення операндів не можна задавати по замовчуванні.
17. Перевантаження оператора привласнення (=). Правила перевантаження операторів. Навести приклади.
Оператор присвоєння (operator=()) - є бінарми оператором, але може бути перевантажений лише як метод класу, а не як дружня функція. Відповідно до цього перевантажений в класі operator= є унарною функцією.
Якщо явно оператор присвоєння не визначений, то автоматично згенерується оператор по замовчуванню, який побайтно буде здійснювати копіювання. В окремих випадках оператор присвоєння може бути замінений конструкторм копії.
Приклад 2.5.8
#include <iostream>
usingnamespaсe std;
class A
{
public:
int i;
A()
{
i = 0;
}
A(int i)
{
this->i = i;
}
A& operator= (A& a)
{
i=a.i;
return *this;
}
show()
{
cout<<" i="<<i<< endl;
}
};
void main()
{
A a, a1(10);
a = a1;
a.show();
}
Перевантажений оператор присвоєння повинен завжди повертати посилання на неконстантний об’єкт. Відповідно до цього тіло оператора повинно закінчуватиcь таким кодом: return *this. Це означає, що operator=() повернув управління об’єкту, який його викликав.
18. Перевантаження оператора інкременту ++ ( префіксна та постфіксна форми). Правила перевантаження операторів. Навести приклади.
Префіксні оператори (operator++(), operator--()) - є унарною операцією. Може перевантажуватись лише як метод класу. Відповідно до цього перевантажені в класі префіксні оператори є функціями без параметрів. Деякі компілятори можуть дозволяти оголошення їх окремих перевантажених версій (де не використовується вказівник this) статичними.
Оголошення префіксного оператора без параметра реалізовує його як чисто префіксний оператор (тобто у формі ++x), а з параметром типу int - постпрефіксним (тобто у формі x++). Даний параметр не використовується в тілі оператора, а є лише прапорцем схеми обчислень префіксного оператора.
Приклад 2.5.13
#include <iostream>
usingnamespaсe std;
class A
{
public:
int i;
A()
{
i = 0;
}
A(int i)
{
this->i = i;
}
intoperator++ (int ) // постпрефіксна форма
{
int i = this->i;
this->i++;
return i;
}
intoperator++ () // префіксна форма
{
i++;
return i;
}
show()
{
cout<<" A::i="<<i<< endl;
}
};
void main()
{
A a(5);
int j =a++; // постпрефіксна форма
cout<<" j="<<j;
a.show();
a.i=5;
j =++a; // префіксна форма
cout<<" j="<<j;
a.show();
}
19. Перевантаження оператора декременту -- ( префіксна та постфіксна форми). Правила перевантаження операторів. Навести приклади.
В 18 питанні відповідь
20. Перевантаження операторів відношення та логічних операторів. Правила перевантаження операторів. Навести приклади.
Всі операції відношення: = (дорівнює), <>(не дорівнює), < (менше), >(більше), <=(менше або дорівнює), >=(більше або дорівнює) дають результат типу boolean. Нижче наведені логічні операції в порядку зменшення їх пріоритету, причому операції, записані в одному пункті мають однаковий пріоритет: 1) Not; 2) And; 3) Or, Xor; 4) =, <>, <, >, <=, >=.
Якщо у виразі не використовують круглі дужки, то логічні операції виконуються в порядку зменшення їх пріоритетів. Операції однакового рангу виконуються зліва направо. Для зміни порядку виконання операцій в логічних виразах використовують круглі дужки.
Наприклад, обчислення виразу
(A=B) and (C<=D)
буде виконуватись в такій послідовності: спочатку визначається значення підвиразу A=B, потім підвиразу C<=D і тільки після цього виконується логічна операція And.
21. Перевантаження оператора виведення із потоку (<<). Правила перевантаження операторів.
Операція «помістити в потік» << – виведення у потік елементів даних вбудованих типів, виведення рядків і виведення значень вказівників. Для виведення виразів необхідно їх розміщувати у круглих дужках (), щоб не було проблем під час виконання операцій обчислення значень у виразах, і операції <<
22. Перевантаження оператора введення в поток (>>). Правила перевантаження операторів. Навести приклади
Операція введення потоку («узяти з потоку» >>) ігнорує у вхідному потоці символи-роздільники (пробіли, знаки табуляції, знак нового рядка). Вона повертає нульове значення (false), коли натрапляє в потоці на ознаку кінця файлу, або повертає посилання на об’єкт, з якого вона викликалася у противному випадку. Вона також установлює біт faіlbіt у разі введення даних неправильного типу і встановлює біт badbіt у випадку неуспішного завершення операції. Кожен потік – це біти стану, застосовувані для керування станом.
23. Поняття наслідування. Просте наслідування. Види наслідування. Управління доступом до базового класу
Наслідування – це процес створення нового класу шляхом додавання нових членів до вже існуючого класу.
Просте наслідування – це створення класу на основі одного.
Множинне наслідування – це створення класу на основі двох чи більше класів.
Статус доступу членів базового класу в похідному класі визначається специфікатором доступу, що використовується для наслідування базового класу.
24. Захищені члени класу. Використання захищених членів.
Захищений рівень доступу пояснити дещо складніше. До захищених членів класу, як і до закритих, користувач звертатися не може. Проте ці члени можуть бути доступні для класів, які є похідними даного класу.
25. Застосування наслідування. Конструктори , деструктори і наслідування. Порядок виклику конструкторів та деструкторів.
Застосування механізму успадкування дозволяє покращити повторне використання коду шляхом використання вже визначених властивостей та 09051004010031000102000018методів (поведінки) базових класів.
Конструктор – це спец. функція, яка призначена для ініціалізації об’єкту і яка викликається автоматично, неявно, після створення об’єкту.
Деструктор – це спец. програма, яка викликається автоматично, неявно в момент знищення об’єкту.
Успадкува́ння (наслідування) — механізм утворення нових 090001010031000102000018класів на основі використання вже існуючих. При цьому властивості і функціональність батьківського класу переходять до класу нащадка(дочірнього).
Порядок виклику деструкторів є таким як у конструкторів, а виконання - зворотнім. Найпершим почне виконуватись деструктор похідного класу, а далі - деструктори вітки породженої останнім в оголошенні батьківським класом. У порядку зворотньому до декларації батьківських класів відпрацють деструктори класів усіх віток від них породжених. Лише по закінченню роботи і закритття батьківських деструкторів закриється деструктор похідного класу.
26. Передача параметрів конструкторам базового класу. Навести приклади
Передача управління конструктору базового класу здійснюється за допомогою конструкції
...(...):base(...){...},
яка розташовується в оголошенні конструктора похідного класу між заголовком конструктора і тілом. Після ключового слова base в дужках розташовується список значень параметрів конструктора базового класу. Очевидно, що вибір відповідного конструктора визначається типом значень в списку.
Для створення об'єктів можна застосовувати конструктори трьох ступенів захисту:
public – при створенні об'єктів в рамках даного простору імен, в методах будь-якого класу — члена даного простору імен;
protected – при створенні об'єктів в рамках похідного класу, у тому числі при побудові об'єктів похідного класу, а також для внутрішнього використовування класом — власником даного конструктора;
private – застосовується виключно для внутрішнього використовування класом-власником даного конструктора. – не успадковується.
27. Множинне наслідування. Віртуальні базові класи. Приклади застосування множиного наслідування
Множинне наслідування – це створення класу на основі двох чи більше класів.
Віртуальні базові класи
Ситуація, зображена на малюнку можлива тільки для мови С++, оскільки на ній вказаний прояв множинного успадкування. Для того, щоб не виникало проблем, необхідно описувати успадкування класів В і С, як віртуальне від класу А. Тоді при створення об’єктів класу D не буде дублюватися клас А.
28. Поліморфізм. Динамічний та статичний поліморфізми. Види зв’язування. Порівняння раннього зв’язування з пізнім.
Поліморфізм - концепція в 0910031000102000018програмуванні, відповідно до якої використовується спільний інтерфейс для обробки даних різних спеціалізованих 0208004000081%типів.
Статичний поліморфізм реалізовується через механізм перевантаження функцій та операторів і віртуальні калси; динамічний - через механізм віртуальних функцій. Надалі говоритиме про поліморфізм як про динамічний.
Існує два терміни, які завжди безпосередньо пов'язують з ООП, це - раннє (early binding) і пізнє зв'язування (late binding) функцій. Суть будь-якого зв'язування полягає в організації виклику подій-функцій. Якщо раннє зв'язування є характеристикою класичних структурних мов програмування, то пізнє зв'язування - є визнчальною рисою мов об'єктного програмування.
Порівняння: В С++ пізнє зв'язування визначається тим, що вихідний код не завжди явно вказує як буде виконуватись програма. Це пов'язане з механізмом звертання і виклику функцій. При пізньому звязуванні виклик функції лише позначається без точного вказування, яка саме функція буде викликатися. Код в момент виконання повинен вирішити, яка функція буде виконуватись.
29. Віртуальні функції . Вказівники на похідні класи.
Віртуальний метод або віртуальна функція — метод об'єкта в 09011010001110100200005010031000102000018об'єктно-орієнтованому програмуванні, різний для базового класу і класу нащадка.
Одним з вказівником являється this.
30. Віртуальні функції. Таблиця віртуальних функцій.
Віртуальна таблиця функцій, віртуальна таблиця методів (00030109118000000200англ. virtual method table, VMT, vtable) — механізм, що використовується реалізаціями 0900200010031000102000018мов програмування для підтримки динамічної диспетчеризації (або зв'язування методів під час виконання).
Віртуальна таблиця об'єкта буде містити адреси динамічно зв'язаних методів. Виклики методів здійснюються шляхом вибирання адреси методу з віртуальної таблиці об'єкта. Віртуальна таблиця одна й та сама для всіх об'єктів одного класу, і через це зазвичай спільно використовується ними. Об'єкти, що належать до класів, сумісних за типом (наприклад, що знаходяться на одній сходинці в ієрархії спадкування), будуть мати віртуальні таблиці з однаковим розміщенням: адреса даного віртуального методу буде знаходитись з одним і тим самим зсувом для всіх класів, сумісних за типом. Таким чином, при вибиранні адреси методу з даного зсуву віртуальної таблиці поверне метод відповідний дійсному класу об'єкта01111000180001000100811811001109%B%5D%22%5BHYPERLINK%20%22%22%5B1%5D%221HYPERLINK%20%22%22%5B1%5D%22%5D"[HYPERLINK "5D%22%5BHYPERLINK%20%22%22%5B1%5D%221HYPERLINK%20%22%22%5B1%5D%22%5D"1HYPERLINK "5D%22%5BHYPERLINK%20%22%22%5B1%5D%221HYPERLINK%20%22%22%5B1%5D%22%5D"]
Як правило компілятор створює окрему віртуальну таблицю для кожного класу. Коли об'єкт уже створений, вказівник на його віртуальну таблицю, який зветься вказівник віртуальної таблиці (00030109118000000200англ. virtual table pointer або 00030109118000000200англ. vpointer), додається як прихований член цього об'єкта (зазвичай як перший член 01111000180001000100811811001109%B%5D%22%5BHYPERLINK%20%22%22%5B2%5D%222HYPERLINK%20%22%22%5B2%5D%22%5D"[HYPERLINK "5D%22%5BHYPERLINK%20%22%22%5B2%5D%222HYPERLINK%20%22%22%5B2%5D%22%5D"2HYPERLINK "5D%22%5BHYPERLINK%20%22%22%5B2%5D%222HYPERLINK%20%22%22%5B2%5D%22%5D"]). Компілятор також генерує «прихований» код в 090011110101010031000102000018конструкторі кожного класу для ініціалізації цього вказівника свого об'єкта адресою відповідної віртуальної таблиці.
31. Чисто віртуальні функції. Абстрактні класи. Навести приклади.
Чистa віртуальна функція абсолютно нічого не робить і недоступна для викликів. Її призначення служити основою (якщо хочете, шаблоном) для заміщуючих функцій в похідних класах.
Абстрактний клас - це клас, який містить хоча б одну чисту віртуальну функцію.