- •2.1 Елементи концепції ооп .. 20
- •1.1 Коментарі.
- •1.2 Прототипи функцій.
- •1.3 Операція розширення області видимості.
- •1.4 Оголошення в операторах.
- •1.5 Перегрузка функцій.
- •1.6 Значення формальних параметрів по замовчуванню.
- •1.7 Посилання та вказівники.
- •1.8 Специфікатор inline
- •1.9 Операції new та delete .
- •1.10 Вказівник на void.
- •1.11 Зв’язування із збереженням типів
- •1.12 Про структури та об’єднання.
- •2.1 Елементи концепції ооп.
- •2.3 Опис протоколу класу.
- •2.4 Передача повідомлень об’єктам.
- •3 Функції-члени.
- •3.1 Функції-члени в межах та за межами формального опису класу.
- •3.2 Про вказівник this.
- •3.3 Перевантаження функцій-членів. Параметри по замовчуванню.
- •4. Конструктори та деструктори.
- •4.1 Поняття про конструктори.
- •4.2 Деструктори.
- •4.3 Досягнення високої ефективності. Конструктор копіювання.
- •5 Глобальні та локальні об’єкти.
- •6 Статична пам’ять та класи.
- •7. Наслідування
- •7.1 Синтаксична реалізація наслідування
- •7.2 Правила доступу до полів даних
- •7.3 Конструктори та деструктори в похідних класах
- •7.4 Використання заміщуючих функцій-членів.
- •7.5 Похідні класи та вказівники.
- •7.6 Ієрархія типів
- •7.7 Множинне наслідування
- •8 Вiртуальнi функцiї та класи
- •8.1 Віртуальні функції.
- •8.2 Чисті віртуальні функції. Абстрактні класи.
- •8.3 Віртуальні деструктори.
- •8.4 Посилання як засіб для реалізації поліморфізму
- •8.5 Технічна реалізація механізму віртуальних функцій.
- •8.6 Віртуальні базові класи
- •8.6.1 Ієрархії класів та наслідування
- •8.6.2 Віртуальні базові класи
- •8.6.3 Виклик конструкторів та віртуальні базові класи.
- •9 Друзі
- •9.1 Дружні класи.
- •9.2 Дружні функції.
- •10 Перевантаження операторiв.
- •10.1 Перевантаження операторів. Загальний підхід.
- •10.2 Перетворення типів.
- •10.3 Перевантаження деяких операторів.
- •10.3.1 Оператор індексування масиву.
- •10.3.2 Перевантаження оператора виклику функції.
- •10.3.3 Оператор доступу до члена класу.
- •10.3.4 Перевантаження операторів інкремента та декремента.
- •10.3.5 Перевантаження операторів управління пам’яттю (new,delete).
- •10.3.6 Перевантаження оператора присвоювання.
- •11.1 Функціональні шаблони
- •11.1.1 Визначення та використання шаблонів функцiй.
- •11.1.2 Перевантаження шаблонiв функцiї.
- •11.1.3 Cпецiалiзованi функцiї шаблона.
- •11.2 Шаблони класів.
- •11.2.1 Визначення шаблонів класу
- •11.2.2 Константи та типи як параметри шаблону
- •11.2.3 Використання шаблонних класів
- •11.2.4 Спецiалiзацiя шаблонiв класу.
- •11.3 Шаблони та конфiгурацiя компiлятора.
- •11.3.1 Шаблони Smart.
- •11.3.2 Шаблони Global I External.
- •12.2 Переадресація вводу-виводу
- •12.3 Розширення потоків для типів кориcтувача
- •12.4 Операції роботи з потоком як дружні
- •12.5 Форматований ввід-вивід
- •12.5.1 Ширина поля
- •12.5.2 Заповнюючий символ
- •12.5.3 Число цифр дійсних чисел
- •12.5.4 Прапорці форматування
- •12.5.5 Маніпулятори
- •12.6 Стан потоку
- •12.7 Файловий ввід-вивід
- •12.7.1 Конструктори файлових потокiв
- •12.7.2 Вiдкриття файлу
- •12.8 Неформатований ввід-вивід
- •12.9 Деякі функції вводу-виводу
- •12.10 Форматування в пам’яті
- •13 Управління виключеннями
- •13.1 Виключення та стек
- •13.2.1 Синтаксис основних конструкцій
- •13.2.1.1 Використання try та сatch
- •13.2.1.2 Використання throw
- •13.2.2 Тип виключення та конструктор копії
- •13.2.3 Пошук відповідного типу виключення
- •13.2.4 Використання terminate() та некеровані виключення
- •13.2.5 Робота з специфікаціями виключень
- •13.2.6 Робота з непередбаченими виключеннями
- •13.2.7 Робота з конструкторами та виключеннями
- •13.2.8 Динамічні об’єкти
- •13.2.9 Передача значень з конструктора та деструктора
- •13.2.10 Робота з ієрархіями виключень
- •13.2.11 Робота з специфічними класами виключень
- •13.3 Структурне управління виключеннями
- •13.3.1 Використання кадрованого управління виключеннями
- •13.3.1.1 Синтаксис
- •13.3.1.2 Про функцію RaiseException()
- •13.3.1.3 Фільтруючий вираз
- •13.3.1.4 Перехоплення виключення процесора
- •13.3.2 Використання завершуючих обробників виключень
8 Вiртуальнi функцiї та класи
8.1 Віртуальні функції.
У всiх прикладах, наведених раніше, повiдомлення, яке посилалось об'єкту, зв'язувалося з конкретним методом на етапi компiляцiї. Раннє зв'язування має переваги, пов'язанi з оптимальнicтю коду. Поряд iз раннiм зв'язуванням в багатьох об'єктно-орiєнтованих мовах пiдтримується механiзм пiзнього зв'язування, тобто коли повiдомлення зв'язується з конкретним методом на етапi виконання програми. Iншими словами, визначається набiр рiзних реакцiй об'єкту на одне i теж повiдомлення, а вже конкретна реакцiя визначається на етапi виконання програми.
Розглянемо, як реалiзована в С++ концепція полiморфiзму за допомогою механiзму вiртуальних функцiй. Вiртуальна функцiя-це специфiчна функцiя-член класу, яка визначається в базовому класi i потiм перевизначається в похiдних . Cукупнiсть класiв, в яких визначається та перевизначається конкретна вiртуальна функцiя називається полiморфiчним кластером, асоцiйованим з даною вiртуальною функцiїю.
Пiдтримка механiзму вiртуальних функцiй в C++ забезпечується спе -цифiчною властивiстю вказiвника на клас. Ця властивiсть полягає в тому, що вказiвник на базовий клас може вказувати не тiльки на об'єкт базового класу, але й на об'єкти будь-якого public-похiдного класу.
Нехай А-деякий базовий клас.
class A{ };
class B:public A{ }
class C:public B{ }
main( )
{A*ра;//-вказiвник на базовий клас;
B*pb;
C*pc;
pb=new B;
pa=pb;
Визначимо екземпляри об'єктiв класу:
main( )
{A a;
B b;
C c;
pa=&b; //вказiвнику на клас A присвоїмо адресу
pa=&c; //вказiвника на В. помилки немає
pb=&а; //компiлятор видасть повiдомлення про помилку.
Для зворотнього присвоєння потрiбно використовувати операцiю явного приведення типу. Приклад:
pb=pa; //помилка
pb=(B*)pa; //-безпомилково
pb=(B*)&a; //-помилка
pb=(B)&a; //-вiрно.
Розглянемо наступний приклад:
class TValue {
protected:
int value;
public:
TValue(int n){
value=n;}
int Getvalue(void)
{return value;}}
Визначимо похiдний клас;
class TMult:public TValue
{protected:
int mult;
public:
TMult(int n,int m):
TValue(n)
{mult=m;}
int GetValue(void)
{return value*mult;}
main( )
{ TValue*base;
base=TMult(10,2)
cout<<base->GetValue;}
//буде надрукованo 10 за рахунок
//механiзму раннього зв'зування
Вiртуальна функцiя-це звичайна функцiя-член класу, яка вiдрiзняється вiд iнших лише наявнiстю ключового слова virtual перед оголошенням функцiї:
virtual int GetValue( )
{ //...}
Якщо оголосити функцію GetValue( ) в обох класах як віртуальну, то в наведеному вище прикладі буде надруковано 20.
Оскiльки вiртуальна функцiя є членом класу, то її визначення може знаходитись за межами формального опису класу. При цьому при визначеннi функцiї ключове слово virtual не потрiбне.
В межах формального опису класу може бути оголошена віртуальна функція
virtual int GetValue( );
Тоді за межами формального опису:
int TValue::GetValue( )
{return value;}
Але чи потрiбне ключове слово virtual при оголошенні функції в усiх членах полiморфiчного кластеру? Виявляється, що достатнім є його наявність лише в першому члені поліморфічного кластера, перед віртуальною функцією самого високого рівня:
class A{
public:
virtual void vf( );};
class B:public A{
public:
void vf( );};
class С:public B{
public:
void vf( );
};
Розглянемо приклад використання вiртуальних функцiй. Нехай необхідно написати програму виводу на екран різних геометричних фігур. Причому проблема полягає в тому, що ми взагалі не знаємо на даному етапі, скільки цих фігур буде, як їх будувати. Але всі фігури мають спільне - вони є геометричними фігурами. Тому використаємо цей факт, написавши деякий клас Shape :
class Shape {
public:
virtual void Draw( );
};
Далі можемо визначити масив вказівників на Shape:
Shape * picture[100];
Тоді для побудови конкретної фігури будемо визначати класи, похідні від Shape, які містять віртуальні функції Draw( ). При такому підході main() -функцію можемо написати зразу, не чекаючи опису конкретних класів з функціями , що малюють фігури:
main( )
{int i=0;
while(i<100&& picture[i]!=0)
{picture[i]->Draw(); i+=1}}
Все, основна програма написана. А далі можемо писати собі похідні класи, скільки завгодно:
class Circle:public Shape
{public:virtual void Draw( )
{\\тіло}
};
class Line:public Shape
{public:virtual void Draw( )
{\\тіло}
};
Тоді виділяємо пам’ять,
picture[0]=new Line;
picture[1]=new Line;
picture[2]=new Circle;
і програма готова !