Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Документ Microsoft Office Word 97 - 2003 (4).doc
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
540.67 Кб
Скачать

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

long * lp;

  / / Створити нове ціле число

lp = new long;

Complex * cp;

  / / Створити новий об'єкт типу Complex

cp = new Complex;

Створений таким чином об'єкт існує до тих пір, поки пам'ять не буде явно звільнена за допомогою операції delete. Як операнд delete повинен бути заданий адресу, повернений операцією new:

delete lp;

delete cp;

Динамічний розподіл пам'яті використовується, насамперед, тоді, коли заздалегідь невідомо, скільки об'єктів знадобиться в програмі і чи знадобляться вони взагалі. За допомогою динамічного розподілу пам'яті можна гнучко керувати часом життя об'єктів, наприклад виділити пам'ять не на самому початку програми (як для глобальних змінних), але, тим не менш, зберігати потрібні дані в цій пам'яті до кінця програми.

Якщо необхідно динамічно створити масив, то потрібно використовувати трохи іншу форму new:

new int [100];

На відміну від визначення змінної типу масив, розмір масиву в операції new може бути довільним, в тому числі обчислюваним в ході виконання програми. (Нагадаємо, що при оголошенні змінної типу масив розмір масиву повинен бути константою.)

Звільнення пам'яті, виділеної під масив, має бути виконане за допомогою наступної операції delete

delete [] address;

4. Один із способів, яким досягається реалізація поліморфізму в мові С + +, полягає у використанні перезавантаження функцій. У C + + дві або більше функцій можуть мати одне і те ж ім'я у випадку, якщо вони відрізняються набором параметрів в інтерфейсі. У такому випадку про функції кажуть, що вони перевантажені. Розглянемо як приклад наступну програму:  # Include <iostream.h>  / / Sqr_it перевантажується три рази  int sqr_it (int i);  double sqr_it (double d);  long sqr_it (long l);  int main ()  {  cout << sqr_it (10) << "\ n";  cout << sqr_it (11.0) << "\ n";  cout << sqr_it (9L) << "\ n";  return 0;  }  int sqr_it (int i)  {  cout << "Inside the sqr_it () function that uses";  cout << "an integer argument. \ n";  return i * i;  }  double sqr_it (double d)  {  cout << "Inside the sqr_it () function that uses";  cout << "a double argument. \ n";  return d * d;  }  long sqr_it (long l)  {  cout << "Inside the sqr_it () function that uses";  cout << "a long argument. \ n";  return l * l;  }

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

Параметри за замовчуванням

Забезпечити значення за замовчуванням для параметрів функції дуже легко. Ви просто привласнюєте значення параметру за допомогою оператора присвоєння С + + прямо при оголошенні функції, як показано нижче:

void some_function (int size = 12, float cost = 19.95) / / ----> Значення за замовчуванням

{

/ / Оператори функції

}

5. Класи - це типи, визначені в конкретній програмі. Визначення класу включає в себе опис, з яких складових частин або атрибутів він складається і які операції визначені для класу.

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

class Complex {

public:

int real; / / речова частина

int imaginary; / / уявна частина

void Add (Complex x);

/ / Додати комплексне число

};

Наведений вище приклад - спрощене визначення класу Complex, що представляє комплексне число. Комплексне числоскладається з дійсної частини - цілого числа real та уявної частини, яка представлена ​​цілим числом imaginary. Real іimaginary - це атрибути класу. Для класу Complex оголошена одна операція або метод - Add.

Визначивши клас, ми можемо створити змінну типу Complex:

Complex number;

Змінна з ім'ям number містить значення типу Complex, тобто містить об'єкт класу Complex. Маючи об'єкт, ми можемо встановити значення атрибутів об'єкту:

number.real = 1;

number.imaginary = 2;

Операція "." Позначає звернення до атрибуту об'єкта. Створивши ще один об'єкт класу Complex, ми можемо додати його до першого:

Complex num2;

number.Add (num2);

Як можна помітити, метод Add виконується з об'єктом. Ім'я об'єкта (або змінної, що містить об'єкт, що, по суті, одне і те ж), в даному випадку, number, записано першим. Через точку записано ім'я методу - Add з аргументом - значенням іншого об'єктакласу Complex, який додається до number. Методи часто називаються повідомленнями. Але щоб послати повідомлення, необхідний одержувач. Таким чином, об'єкту number надсилається повідомлення Add з аргументом num2. Об'єкт numberприймає це повідомлення і складає своє значення зі значенням аргументу повідомлення. Оператор непрямого вибору – це спеціальний символ, що складається з мінуса та знаку більше „->”.

Оператор прямого вибору використовується тоді, коли доступ до об’єкту класу у програмі виконується безпосередньо. Оператор непрямого (опосередкованого) вибору використовується, коли доступ до об’єкту класу у програмі виконується опосередковано через покажчик на об’єкт.

Доступ до закритих та захищених методів та полів здійснюється лише за допомогою відкритих методів класу або за допомогою друзів класу.

6.Клас в С++ – це практична реалізація абстрактного типу даних засобами мови програмування С++[4]. Фактично клас – це визначений програмістом нестандартний тип даних, тому поняття полів і методів класу повністю співпадають з аналогічними поняттями абстрактного типу даних. Процес визначення класу складається з двох частин.

Перша частина – це опис класу. В цій частині визначається структура класу, а саме кількість та типи полів(властивостей) класу, кількість методів, кількість та типи вхідних параметрів методів, а також типи результатів виконання методів. Крім того на цьому етапі визначається область бачимості полів та методів.

Опис класу починається з ключового слова class, за яким слідує назва класу. Він складається з розділів, які виділяються модифікаторами public, private, protected, що є заголовками розділів і визначають їх початок та область бачимості полів та методів, розташованих у розділі.

У розділах із заголовками public розміщуються загальнодоступні поля та методи, які використовуються для інтерфейсу об’єктів даного класу з програмою. Доступ до цих полів і методів може бути здійснений прямим зверненням.

У розділах із заголовками private розміщуються закриті дані, доступ до яких може бути здійснений лише за допомогою методів самого класу або за допомогою друзів класу. Поняття друзів класу буде розглянуто пізніше.

Розділи із заголовками protected містять дані, доступ до яких може бути здійснений за допомогою методів самого класу, за допомогою методів породжених класів або за допомогою друзів класу.

Розділ починається заголовком та закінчується заголовком іншого розділу або межею опису класу. Опис класу обмежується заголовком класу та фігурними скобками. „{”, „}”. Кількість розділів не лімітується. Клас можескладатися як з одного розділу, так із кількох, порядок розташування розділів довільний в межах опису класу. В описі класу може існувати кілька розділів з однаковими заголовками. Перший розділ опису класу може бути без заголовку. В цьому випадку вважається, що заголовком розділу є модифікатор private.

Друга частина визначення класу – це опис методів класу. В цій частині реалізуються засобами мови програмування алгоритми методів класу.

Обидві частини є обов’язковими при визначенні класу і жодна з них не може бути пропущена. Опис класу та опис методів класу повинні бути розміщені у одному файлі. Зазвичай їх розміщують у окремих файлах із розширенням „h” і потім включають за допомогою директиви #include до кожного з тих файлів проекту, в яких використовуються об’єкти даного класу.

Розглянемо приклад визначення класу.

Опис класу:

class MyClass

{

int i; //розділ із типом доступу private

public: //розділ із типом доступу public

int get_i();

void set_i(int);

};

Опис методів класу:

int MyClass::get_i() { return i; }

void MyClass::set_i(int x) { i=x; return; }

Якщо методи класу прості і складаються всього лише з кількох операторів, то їх опис можна розмістити прямо у описі класу.

клас – це абстрактний тип даних. Для того щоб використати розроблений клас у програмі необхідно об’явити змінну даного типу. Така змінна буде називатись об’єктом даного класу. Таким чином об’єкт класу – це конкретна змінна (екземпляр) класу (даного типу інформаційної структури).

Об’явити об’єкт даного класу можна таким же чином, як і змінну будь-якого іншого стандартного або заданого користувачем типу. Наприклад об’явити об’єкт показаного вище класу MyClass при умові, що даний клас описаний у файлі MyClass.h, який знаходиться у одному каталозі з проектом, можна наступним чином:

#include “MyClass.h”

MyClass MyObj;

7. Клас в С++ – це практична реалізація абстрактного типу даних засобами мови програмування С++[4]. Фактично клас – це визначений програмістом нестандартний тип даних, тому поняття полів і методів класу повністю співпадають з аналогічними поняттями абстрактного типу даних

Конструктор – це функція метод класу з таким самим ім’ям, як у класу. Цей метод призначений для створення та ініціалізацію об’єктів класу, виділення пам’яті під об’єкти та присвоєння початкових значень полям об’єкту.

Деструктор – це функція метод класу, яка відповідає за коректне вивільнення пам’яті при знищенні об’єкту. Деструктор завжди має ім’я таке ж, що і у класу, перед яким ставиться символ „~”.

Конструктори і деструктори не можуть повертати значень і тому при їх описанні відсутній тип результату.

Конструктор може мати вхідні параметри, а може не мати. Конструктор, який не має вхідних параметрів називається конструктором за замовчуванням.

Клас може не містити цих функцій у явному вигляді. Тоді розподіл пам’яті та ініціалізація об’єкту виконуються системою автоматично стандартним шляхом. Але оскільки стандартна процедура не враховує особливостей класу, то така процедура може бути неефективною і часто навіть може призводити до серйозних помилок в роботі програми, тому бажано при розробці класів розробляти конструктори та деструктори.

Клас може мати кілька конструкторів і лише один деструктор. Для прикладу добавимо конструктор в розглянутий вище клас MyClass.

class MyClass

{

int i; //розділ із типом доступу private

public: //розділ із типом доступу public

MyClass(){i=0;}//Конструктор. У описі відсутній тип результату.;

//Вхідні параметри відсутні. Це конструктор за замовчуванням;

inline int get_i(){ return i; };

inline void set_i(int) { i=x; return; };

};

В даному випадку конструктор дуже простий і не потребує параметрів при визові. Це конструктор по замовчуванню. Розглянемо більш складний приклад.

class MyClass

{

int i; //розділ із типом доступу private

public: //розділ із типом доступу public

MyClass(){i=0;}//Конструктор. У описі відсутній тип результату.;

//Вхідні параметри відсутні. Це конструктор за замовчуванням;

MyClass(int a){i=a;}//Це також конструктор, але з параметром.

inline int get_i(){ return i; };

inline void set_i(int) { i=x; return; };

};

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

Наприклад:

class CDate

{

int mounth, day, year;

public: GetDate () {return Day};

SetDate (int, int, int);

};

Тут функція GetDate автоматично визначається як вбудовується, у той час як SetDate, та інші функції, описані поза класом CDate будуть організовані за звичайними правилами мови С + +. Для визначення функції-члена класу за межами опису класу, необхідно визначити її де-небудь у програмі після визначення класу, членом якого вона є. У той же час, функції-члени різних класів можуть мати однакові назви, наприклад:

class CStr

{/ / Клас рядків

char * PointString; / /

int Length; / / дані

int Status; / /

public: void SetString (char *) / / функції-методи

void Clear (); / / класу

/ / Інші методи класу

...

};

class CMatrix

{/ / Клас матриць

char * PointMatr;

int Direct; / / дані

int TypeMatr; / /

public: void SetMatr (char *); / / функції-методи

void Clear (); / / класу

/ / Інші методи класу

...

};

У наведеному прикладі класи CStr і CMatrix містять функції-члени класу Clear () однойменні в різних класах. Ясно, що в цьому випадку виникає проблема визначення імені класу, до якого належить описувана функція при програмуванні тіла функції.

Для вирішення цієї проблеми в С + + введена операція області видимості ::. Ця операція дозволяє вказати компілятору, до якого з класів належить обумовлена ​​функція. Приклад, наведений нижче, показує як визначаються функції для раніше описаних класів CStr і CMatrix.

void CStr :: Clear () / / Визначення функції Clear () для класу CStr

{

ZeroMemory (PointString, Length);

}

void CMatrix :: Clear () / / Визначення функції Clear () для класу CMatrix

{

ZeroMemory (PointMatr, Direct);

}

C + + визначає кілька типів функцій, які можна оголошувати тільки у вигляді членів класу - це називається «спеціальними функції-членами». Ці функції впливають на спосіб об'єкти заданого класу створюються, видалено, копіюється і перетворюється в об'єкти інших типів. Інша важлива властивість багато з цих функцій щоб їх можна було викликати неявно (компілятором).

Спеціальні функції-члени, описані в цьому розділі, наступним чином:

Конструктори. Включення автоматичної ініціалізації об'єктів.

деструктори. Виконайте очистку після того як об'єкти явно чи неявно знищені.

функції перетворення. Перетворення між типами класу і іншими типами.

функція оператора new. Динамічно виділяє сховище.

функція видалення оператора. Зберігання виділеного за допомогою випусків створити оператор.

Оператор присвоювання () operator =. Використовується, коли призначення виконується.

Елементи у попередньому списку можуть бути обумовленою користувачем, для кожного класу.

Спеціальні функції-члени підкоряються тим же правилам доступу, що й інші функції елементів. Правила доступу, описаних в Управління доступом до членів.

9.

Покажчик this

Кожен об'єкт містить свій екземпляр полів класу. Методи місця в класі не займають і не дублюються для кожного об'єкта. Єдиний екземпляр методу використовується всіма об'єктами спільно, тому нестатичних метод повинен "знати", для якого об'єкта він викликаний.

Кожен нестатичних метод, крім явно оголошених параметрів, отримує ще один прихований параметр: константних покажчик на об'єкт, для якого він викликаний. У С + + це покажчик позначається зарезервованим словом this. Коли ім'я параметра методу збігається з ім'ям поля класу, доступ до поля виконується через цей покажчик (наприклад, this -> num).

Вираз * this являє собою разименованія покажчика і має тип визначається класу. Зазвичай цей вираз повертається в якості результату, якщо метод повертає посилання на свій клас (return * this;).

Для ілюстрації використання покажчика this додамо в наведений вище клас monster новий метод, який повертає посилання на найбільш здорового (поле health) з двох монстрів, один з яких викликає метод, а інший передається йому як параметр (метод потрібно помістити в секцію public опису класу) :

monster & the_best (monster & M)

{

if (health> M.get_health ())

  return * this;

return M;

}

10. Конструктором

Функція-член класу з тим же ім'ям, що і у класу, називається конструктором. Вона використовується для побудови об'єктів цього класу. Конструктор не повинен повертати жодного значення, навіть void.

class Complex

  {Private:

     double r, m;

    public:

     Complex (double r, double m): r (r), m (m) {}

    ...

   };

Якщо клас має конструктор, всі об'єкти цього класу будуть проініціалізовані. Якщо конструктору потрібні параметри, вони мають бути надані.

Коли для класу оголошений конструктор, не можна користуватися списком ініціалізації в якості ініціалізатора.

Complex c1 (5, -2);

Complex c2 = {5, -2}; / / Правильно

/ / Помилка - клас Complex має конструктор

конструктор умовчання

Конструктор умовчання класу Х - це конструктор класу Х, що викликається без параметрів. Конструктор умовчання зазвичай має вигляд Х :: Х (), однак і конструктор, який може викликатися без параметрів, тому що має параметри з умовчанням, наприклад, Х :: Х (int = 0), також вважається конструктором умовчання. За відсутності інших оголошених конструкторів, конструктор умовчання генерується компілятором.

class Complex

  {Private:

     double r, m;

    public:

     Complex (): r (0), m (0) {}

    ...

   };

  

Complex x;

   / / Виклик конструктора умовчання

class Complex

  {Private:

     double r, m;

    public:

     Complex (double nr = 0, double nm = 0): r (nr), m (nm) {}

    ...

   };

  

Complex y1 (-6, 3); / / Виклик конструктора з параметрами

Complex y2; / / Конструктор викликається як конструктор умовчання

Конструктор копіювання для класу Х - це конструктор, який може бути викликаний для копіювання об'єкта класу Х, тобто такий конструктор, який може бути викликаний з одним параметром - посиланням на об'єкт класу Х. Наприклад, X :: X (const X &) і X :: X (X &, int = 0) є конструкторами копіювання.

За відсутності оголошених конструкторів копіювання компілятор генерує публічний конструктор копіювання. Генерований конструктор копіювання виконує побітовое копіювання об'єкта. Цей метод годиться лише за відсутності в об'єкті покажчиків, які зберігають адреси динамічно розподіленої пам'яті. Згенерований конструктор скопіює адресу, а не вміст пам'яті, таким чином, два різних об'єкта будуть посилатися на один і той ділянку пам'яті і мінятися синхронно, що не є очікуваним поведінкою. У такому випадку програміст обов'язково повинен сам написати конструктор копіювання, який буде, зокрема, копіювати вміст динамічно розподіленої пам'яті.

Однак у тих випадках, коли конструктор копіювання за замовчуванням має правильний сенс, краще покладатися на це замовчування. Це коротше, а читають код повинні розуміти умовчання. Крім того, компілятор знає про це умовчанні і про можливості його оптимізації. А написання почленного копіювання класів з великою кількістю членів даних вручну - заняття виснажливе, і при цьому можна наробити масу помилок.

Конструктор копіювання - і визначається користувачем, і генерується компілятором - використовується:

при ініціалізації змінних;

при передачі аргументів;

при поверненні значення з функції;

при обробці виключень.

Семантика цих операцій щодо визначення збігається з семантикою ініціалізації.

Complex x = 2;

Complex y = Complex (2, 0); / / Створює Complex (2), потім копіює його в x

/ / Створює Complex (2, 0), потім копіює його в у

Від викликів конструктора копіювання легко позбутися. З тим же успіхом можна записати наступне.

Complex x (2);

Complex y (2, 0); / / проініціалізувати x значенням 2

/ / Проініціалізувати у значенням (2, 0)

11, конструктором

Функція-член класу з тим же ім'ям, що і у класу, називається конструктором. Вона використовується для побудови об'єктів цього класу. Конструктор не повинен повертати жодного значення, навіть void.

class Complex

  {Private:

     double r, m;

    public:

     Complex (double r, double m): r (r), m (m) {}

    ...

   };

Якщо клас має конструктор, всі об'єкти цього класу будуть проініціалізовані. Якщо конструктору потрібні параметри, вони мають бути надані.

Коли для класу оголошений конструктор, не можна користуватися списком ініціалізації в якості ініціалізатора.

Complex c1 (5, -2);

Complex c2 = {5, -2}; / / Правильно

/ / Помилка - клас Complex має конструктор

конструктор умовчання

Конструктор перетворення

Конструктор з одним параметром задає перетворення типу свого параметра до типу свого класу.

Конструктор з одним параметром не обов'язково викликається явно.

class X

  {Private:

     int x;

    public:

     X (int n);

    ...

   };

X :: X (int n) {x = n;}

X a = 1; / / Еквівалентно X a = X (1)

Однак неявне перетворення може бути небажано в деяких випадках.

class Str

  {Private:

     char * str;

    public:

     Str (int n) {str = new char [n]; * str = 0;}

     Str (const char * p) {str = new char [strlen (p) + 1]; strcpy (str, p);}

     ~ Str () {if (str) delete [] str;}

   };

 Str s = 'a'; / / Створення рядки з int ('a') елементів

Неявне перетворення можна придушити, оголосивши конструктор з модифікатором explicit. Такий конструктор буде викликатися тільки явно.

class Str

  {Private:

     char * str;

    public:

     explicit Str (int n) {str = new char [n]; * str = 0;}

     Str (const char * p) {str = new char [strlen (p) + 1]; strcpy (str, p);}

     ~ Str () {if (str) delete [] str;}

   };

  

Str s1 = 'a';

Str s2 (10); / / Помилка - немає неявного перетворення char в Str

/ / Правильно - створюється рядок з 10 символів

Деструкторы

Функция-член класса Х с именем ~Х называется деструктором. Она используется для разрушения значения класса Х непосредственно перед разрушением содержащего его объекта. Деструктор не имеет параметров и возвращаемого типа, нельзя задавать даже void.

Деструкторы автоматически вызываются, когда

  • автоматический или временный объект уходит из области действия;

  • завершается программа (для статически сконструированных объектов);

  • используется операция delete для объектов размещенных операцией new.

Деструктор может также вызываться явным образом.

class X

{ private:

int n;

public:

X();

~X();

};

X xx;

xx.~X();

// Явный вызов деструктора

12.

12. Спадкування являє собою здатність похідного класу успадковувати характеристики існуючого базового класу. Наприклад, припустимо, що у вас є базовий клас employee:

class employee

{

public:

employee (char *, char *, float);

void show_employee (void);

private:

char name [64];

char position [64];

float salary;

};

Далі припустимо, що вашій програмі потрібно клас manager, який додає наступні елементи даних в клас employee:

float annual_bonus;

char company_car [64];

int stock_options;

У даному випадку ваша програма може вибрати два варіанти: по-перше, програма може створити новий клас manager, який дублює багато елементів класу employee, або програма може породити клас типу manager з базового класу employee. Породжуючи клас manager з існуючого класу employee, ви знижуєте обсяг необхідного програмування і виключаєте дублювання коду всередині вашої програми.

Для визначення цього класу ви повинні вказати ключове слово class, ім'я manager, наступне за ним двокрапку і ім'я employee, як показано нижче:

Похідний клас / / -----> class manager: public employee {<------- / / Базовий клас

/ / Тут визначаються елементи

};

Ключове слово public, яке передує ім'я класу employee, вказує, що загальні (public) елементи класу employee також є загальними і в класі manager.

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

13. ДРУЗІ КЛАСУ

Іноді виникає необхідність, щоб якась функція, що не є членом класу мала доступ до закритих та захищених полів об'єктів даного класу. У С++ є така можливість. Для цього необхідно і достатньо оголосити дану функцію другом цього класу. Зробити це можна за допомогою ключового слова “friend”. Розглянемо це на прикладі.

class friend_prob

{

private:

int status;

public:

int get_status(){return status;}

void set_status(int x){ status=x; return;}

//функція prob_friend оголошується другом класу

void friend prob_friend(friend_prob &obj );

};

void prob_friend( friend_prob &obj)

{

//функція друг здійснює доступ до закритого члена

//класу шляхом прямого звертання.

obj.status++;

return;

}

У даному прикладі функція prob_friend (friend_prob &obj) описана, як друг класу friend_prob. Це дозволяє їй дістати доступ до закритого поля даного класу status. Зверніть увагу на те, що, оскільки в програмі може існувати одночасно декілька об'ектів даного класу, такій функції необхідно як параметр передавати покажчик на об'єкт, з яким вона повинна працювати в даний момент.

Аналогічним чином можна описати метод іншого класу або навіть цілий клас, як друг даного класу. Наприклад, можна визначити клас а, як друг класу b. Тоді методи об'єктів класа а отримають доступ до закритих та захищених полів об'єктів класу b.

Розглянемо приклад.

class MyClass1;//випереджуючий неповний опис класу MyClass1

class MyClass2

{

private://розділ закритих полів класу

int status;

public://розділ відкритих методів класу

int get_status(){return status;}

void set_status(int x){status=x;return;}

friend MyClass1;//об’являємо клас MyClass1 другом класу MyClass2

};

class MyClass1

{

public:

//метод set_status класу MyClass1 модифікує закрите

//поле status класу MyClass2 шляхом прямого звернення

void set_status(MyClass2& obj,int x){obj.status=x;return;}

};

У даному прикладі клас MyClass1 оголошується як друг класу MyClass. Це дозволяє методу set_status класу MyClass1 звертатися до закритого поля status класу MyClass2.

Зверніть увагу на те, що, для забезпечення можливості зробити це оголошення, довелося застосувати випереджуючий неповний опис класу MyClass1. Без такого опису компілятор видав би помилку. Крім того методу set_status класу MyClass1 для реалізації доступу до конкретного об'єкту необхідно знати адресу цього об'єкту, тому, як один з аргументів, йому передається покажчик на об'єкт класу MyClass2.

Наявність механізму установлення дружніх відносин між класами дозволяє моделювати досить складні відносини між класами, що значно полегшує створення програм для вирішення складних практичних завдань

Покажчик this

Кожен об'єкт містить свій екземпляр полів класу. Методи місця в класі не займають і не дублюються для кожного об'єкта. Єдиний екземпляр методу використовується всіма об'єктами спільно, тому нестатичних метод повинен "знати", для якого об'єкта він викликаний.

Кожен нестатичних метод, крім явно оголошених параметрів, отримує ще один прихований параметр: константних покажчик на об'єкт, для якого він викликаний. У С + + це покажчик позначається зарезервованим словом this. Коли ім'я параметра методу збігається з ім'ям поля класу, доступ до поля виконується через цей покажчик (наприклад, this -> num).

Вираз * this являє собою разименованія покажчика і має тип визначається класу. Зазвичай цей вираз повертається в якості результату, якщо метод повертає посилання на свій клас (return * this;).

Для ілюстрації використання покажчика this додамо в наведений вище клас monster новий метод, який повертає посилання на найбільш здорового (поле health) з двох монстрів, один з яких викликає метод, а інший передається йому як параметр (метод потрібно помістити в секцію public опису класу) :

monster & the_best (monster & M)

{

if (health> M.get_health ())

  return * this;

return M;

}

14. Перевантаження операцій

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

Таблиця 5.1.

. . *? ::: # # # Sizeof

Перевантаження операцій здійснюється за допомогою функцій спеціального виду (функцій-операцій) і підпорядковується наступним правилам:

зберігаються кількість аргументів, пріоритети операцій і правила асоціації (справа наліво або зліва направо) в порівнянні з використанням в стандартних типах даних;

не можна перевизначити операцію по відношенню до стандартних типів даних;

функція-операція не може мати аргументів за замовчуванням;

функції-операції успадковуються (за винятком =);

Функцію-операцію можна визначити трьома способами: вона повинна бути або методом класу, або дружньої функцією класу, або звичайною функцією. У двох останніх випадках функція повинна приймати хоча б один аргумент, має тип класу, покажчика або посилання на клас (особливий випадок: функція-операція, перший параметр якої - стандартного типу, не може визначатися як метод класу).

Функція-операція містить ключове слово operator, за яким слід знак переобумовленої операції:

тип operator операція (список параметрів) {тіло функції}

Перевантаження унарних операцій

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

class monster

{... monster & operator + + () {+ + health; return * this;}}

monster Vasia;

cout << (+ + Vasia). get_health ();

Якщо функція визначається поза класом, вона повинна мати один параметр типу класу:

class monster

{... friend monster & operator + + (monster & M);};

monster & operator + + (monster & M) {+ + M.health; return M;}

Якщо не описувати функцію всередині класу як дружню, потрібно враховувати доступність змінюваних полів (в даному випадку поле health заблоковано ззовні, так як описано з специфікатором private, тому для його зміни потрібне використання відповідного методу, що не описаного в наведеному прикладі).

Операції Постфіксний инкремента і декремента повинні мати перший параметр типу int. Він використовується тільки для того, щоб відрізнити їх від префиксной форми:

class monster

{... monster operator + + (int) {monster M (* this); health + +; return M;}};

monster Vasia;

cout << (Vasia + +). get_health ();

15. Перевантаження операцій

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

Таблиця 5.1.

. . *? ::: # # # Sizeof

Перевантаження операцій здійснюється за допомогою функцій спеціального виду (функцій-операцій) і підпорядковується наступним правилам:

зберігаються кількість аргументів, пріоритети операцій і правила асоціації (справа наліво або зліва направо) в порівнянні з використанням в стандартних типах даних;

не можна перевизначити операцію по відношенню до стандартних типів даних;

функція-операція не може мати аргументів за замовчуванням;

функції-операції успадковуються (за винятком =);

Функцію-операцію можна визначити трьома способами: вона повинна бути або методом класу, або дружньої функцією класу, або звичайною функцією. У двох останніх випадках функція повинна приймати хоча б один аргумент, має тип класу, покажчика або посилання на клас (особливий випадок: функція-операція, перший параметр якої - стандартного типу, не може визначатися як метод класу).

Функція-операція містить ключове слово operator, за яким слід знак переобумовленої операції:

тип operator операція (список параметрів) {тіло функції}

Перевантаження бінарних операцій

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

class monster

{...

bool operator> (const monster & M)

{

if (health> M.get_health ()) return true;

return false;

}

};

Якщо функція визначається поза класом, вона повинна мати два параметри типу класу:

bool operator> (const monster & M1, const monster & M2)

  {If (M1.get_health ()> M2.get_health ()) return true;

return false;

  }

16. Для перевантаження (розширення дії) операції введення >> необхідно визначити операцію-функцію виду:

istream & operator >> (istream & in, новий_тіп & ім'я)

{/ / Будь-які оператори для параметра нового типу.

in >> ... / / Введення значень нового типу.

return in; / / Повернення посилання на об'єкт класу istream.

}

Тут новий_тіп - тип, визначений користувачем, тобто деякий клас або його окремий випадок - структурний тип. Основна відмінність від перевантаження операції виведення - необхідність в якості другого параметра використати посилання. Для вже введеного на попередніх кроках структурного типу "точка тривимірного евклідового простору"можна за допомогою перевантаження операції введення >> дуже витончено визначити послідовність вводу з консолі значень координат

/ / OOР10_2.СРР - перевантаження операцій введення >> і виведення <<.

# Include <iostream.h>

/ / Визначення класу "службовець":

struct employee

{

char name [50]; / / Прізвище.

long salery; / / Оклад.

int age; / / Вік.

};

/ / Визначення операції-функції, "розповсюджує"

/ / Дія операції введення "на операнд типу employee:

istream & / / Тип значення, що повертається.

operator >> (istream & input, employee & em)

{

cout << "\ n \ nВведіте відомості про службовця:" <<

"\ NФамілія:";

input >> em.name;

cout << "Оклад:";

input >> em.salery;

cout << "Вік:";

input >> em.age;

return input;

}

/ / Прототип операції-функції для перевантаження операції <<:

ostream & operator << (ostream &, employee);

void main ()

{

employee E; / / Визначено об'єкт класу employee.

cin >> E;

cout << E;

}

/ / Визначення операції-функції для перевантаження

/ / Операції <<:

ostream & operator << (ostream & out, employee e)

{

out << "\ nВведени такі відомості про службовця:";

out << "\ nІмя:" << e.name;

out << ", оклад:" << e.salery << "руб.";

out << ", вік:" << e.age << "років. \ n";

return out;

}

17. Віртуальні функції

18.Чисто віртуальні функції.

Віртуальні функція класу називається чисто віртуальною якщо вона в класі не має коду і описується:

Virtual void evirt () =0 – будь-яке значення.

Вона без коду і її викликати в процесі програми не можна.

Абстрактні класи

Механізм абстрактних класів служить для представлення загальних понять, які фактично використовуються лише для породження більш конкретних понять. Абстрактний клас можна також вживати як визначення інтерфейсу, в якому похідні класи забезпечують різноманітність реалізацій.

Абстрактний клас - це клас, який може використовуватися лише в якості базового класу для деякого іншого класу. Клас є абстрактним, якщо він містить хоча б одну чисту віртуальну функцію.

Віртуальна функція називається чистою, якщо в оголошенні функції всередині оголошення класу заданий чистий специфікатор = 0.

class Shape

 {Public:

    virtual void draw () = 0;

    ...

  };

/ / Чистий віртуальна функція

Абстрактний клас не можна вживати в якості типу об'єктів, типу параметрів функцій, типу повертається функцією значення або як тип при явному приведенні типу. Можна, однак, оголошувати покажчики і посилання на абстрактний клас.

Shape s;

Shape * s;

Shape f ();

void f (Shape s);

Shape & f (Shape & s); / / Помилка: об'єкт абстрактного класу

/ / Все правильно

/ / Помилка

/ / Помилка

/ / Все правильно

Віртуальні класи

Чисті віртуальні функції успадковуються і залишаються чистими віртуальними функціями, таким чином, похідний клас, в якому чиста віртуальна функції не перевизначена, залишається абстрактним класом

Хоча операція дозволу видимості і являє обхідний шлях, що дозволяє уникнути неоднозначності при складному спадкуванні, ви, тим не менш, можете захотіти, щоб ваш похідний клас успадковував тільки один екземпляр деякого базового класу. Цього можна досягти застосуванням ключового слова virtual при специфікації успадкованого класу. Наприклад, у разі розглянутого раніше ромбоподібного спадкування:

class A

{

protected:

int iData;

public:

void f ();

...

};

class B: virtual public A

{...};

class C: virtual public A

{...};

class D: public B, public C

{

/ / Містить тільки один екземпляр класу A

...

};

int main (void)

{

D d;

d. f ();

d. iData = 10; / / помилка: елемент даних недоступний

}

Якби ми спробували використовувати множинне спадкування без використання ключового слова virtual, то компілятор видав би повідомлення про помилку, так як класи B і C в цьому випадку успадковують свою копію класу A. Така копія називається подоб'екти. Кожен з двох подоб'ектов містить власну копію базового класу A, включаючи f (). Отже, виникне неоднозначність відносного того, у якій з двох копій класу A викликати функцію f (). Для усунення неоднозначності використовують ключове слово virtual, що забезпечує успадкування класами B і C єдиного загального підоб'єкту базового класу A. Так як у нас тепер є тільки одна копія класу A, то неоднозначність при зверненні до базового класу усувається.

Необхідно відзначити, що деструктори базового класу обов'язково повинні бути віртуальними. Припустимо, щоб видалити об'єкт породженого класу, ви виконали delete над покажчиком базового класу, що вказує на породжений клас. Якщо деструктор базового класу не є віртуальним, тоді delete, будучи звичайним методом, викличе деструктор для базового класу, замість того щоб запустити деструктор для породженого класу. Це призведе до того, що буде вилучена тільки та частина об'єкта, яка відноситься до базового класу.

19. Від того, з яким специфікатором доступу оголошується спадкування базового класу, залежить статус доступу до членів похідного класу. Загальна форма успадкування класів має наступний вигляд:

class імя_класса: доступ імя_класса {

....

};

Тут доступ визначає, яким способом успадковується базовий клас. Специфікатор доступ може приймати три значення - private, public і protected. У разі, якщо специфікатор доступ опущений, то за замовчуванням мається на увазі на його місці специфікатор public. Якщо специфікатор доступ приймає значення public, то всі публічні і захищені члени базового класу стають відповідно публічними і захищеними членами похідного класу. Якщо специфікатор доступ має значення private, то всі публічні і захищені члени базового класу стають приватними членами похідного класу. Якщо специфікатор доступ приймає значення protected, то всі публічні і захищені члени базового класу стають захищеними членами похідного класу. Для того щоб засвоїти всі ці перетворення

private

protected

public

Всегда недоступна, независимо от доступа вывода

Private в производном классе если используется закрытый вывод

Private в производном классе если используется закрытый вывод

 

Protected в производном классе если используется защищенный вывод

Protected в производном классе если используется защищенный вывод

 

Protected в производном классе если используется открытый вывод

Открытый в производном классе если используется открытый вывод

20. Шаблони функцій - спеціальні функції, які можуть працювати з універсальними типами. Це дозволяє нам створювати шаблон функції, функціональність якого може бути адаптована більше ніж до одного типу або класу, не повторюючи весь код для кожного типу.

У C + + це може бути досягнуто, використовуючи шаблонні параметри. Шаблонний параметр - спеціальний вид параметра, який може використовуватися, щоб передати тип як параметр: точно так само, як параметри регулярної функції можуть використовуватися, щоб передати значення до функції, шаблонні параметри дозволяють передавати також типи до функції. Ці шаблони функцій можуть використовувати ці параметри, як ніби вони були будь-яким іншим нормальним шрифтом.

Формат для того, щоб оголосити шаблони функцій з параметрами типу:

template <class identifier> function_declaration;

шаблон <ідентифікатор імені типу> function_declaration;Єдина різниця між обома прототипами - використання або ключового слова class або ключового слова typename. Його використання неясно, так як обидва пресування має точно те ж саме значення і поводиться точно той же самий шлях.

Наприклад, щоб створити шаблонну функцію, яка повертає більший з двох об'єктів, які ми могли використовувати:

template <class myType>

myType GetMax (myType a, myType b) {

 return (a> b? a: b);

}

Тут ми створили шаблонну функцію з myType як його шаблонний параметр. Цей шаблонний параметр представляє тип, який ще не був зазначений, але це може використовуватися в шаблонної функції, як ніби це був нормальний шрифт. Оскільки можна бачити, шаблон функції, GetMax повертає великі з двох параметрів цього все ще невизначеного типу.

Щоб використовувати цей шаблон функції, ми використовуємо наступний формат для виклику функції:

function_name <type> (parameters);

Наприклад, щоб викликати GetMax, щоб порівняти два цілочисельних значення типу int ми можемо записати:

int x, y;

GetMax <int> (x, y);

Коли компілятор зустрічається з цим дзвінком у шаблонну функцію, це використовує шаблон, щоб автоматично генерувати функцію, яка замінює кожна поява myType типом, який передають як фактичний шаблонний параметр (int в цьому випадку), і потім викликає це. Цей процес автоматично виконується компілятором і невидимий для компанії-виробника телевізійних програм.

Ось весь приклад:

/ / Function template

# Include <iostream>

using namespace std;

template <class T>

T GetMax (T a, T b) {

  T result;

  result = (a> b)? a: b;

  return (result);

}

int main () {

  int i = 5, j = 6, k;

  long l = 10, m = 5, n;

  k = GetMax <int> (i, j);

  n = GetMax <long> (l, m);

  cout << k << endl;

  cout << n << endl;

  return 0;

}

У цьому випадку ми використовували T в якості шаблонного назви параметра замість myType, тому що це коротше і фактично є дуже загальним шаблонним назвою параметра. Але можна використовувати будь-який ідентифікатор, який Ви любите.

У прикладі вище ми використовували шаблон функції GetMax () двічі. У перший раз з параметрами типу int і другий з параметрами типу long. Компілятор інстанціювати і потім викликав щоразу адекватну версію функції.

Оскільки можна бачити, тип, T використовується в межах шаблонної функції GetMax (), парною, щоб оголосити нові об'єкти того типу:

T result;

Тому, result буде об'єктом того ж самого типу як параметри a і b, коли шаблон функції інстанціруют з певним типом.

У цьому конкретному випадку, де універсальний тип T використовується як параметр для GetMax, компілятор може дізнатися автоматично, якого тип даних повинен інстанціювати, не маючи необхідність явно вказувати це в межах кутових дужок (як, ми зробили перш, ніж вказати <int> і <long>). Таким чином, ми, можливо, записали замість цього:

int i, j;

GetMax (i, j);

І починаючи з i і починаючи з j мають тип int, і компілятор може автоматично дізнатися, що шаблонний параметр може тільки бути int. Цей неявний метод призводить точно до того ж самого результату:

/ / Function template II

# Include <iostream>

using namespace std;

template <class T>

T GetMax (T a, T b) {

  return (a> b? a: b);

}

int main () {

  int i = 5, j = 6, k;

  long l = 10, m = 5, n;

  k = GetMax (i, j);

  n = GetMax (l, m);

  cout << k << endl;

  cout << n << endl;

  return 0;

}

Зауважте, як у цьому випадку, ми викликали наш шаблон функції GetMax (), явно не вказуючи тип між кутовими дужками <>. Компілятор автоматично визначає що типи 1, необхідні на кожному виклику.

Оскільки наша шаблонна функція включає тільки один шаблонний параметр (class T), і сам шаблон функції приймає два параметри, обидва з цього типу T, ми не можемо викликати наш шаблон функції з двома об'єктами різних типів як параметри:

int i;

long l;

k = GetMax (i, l);

Це не було б коректно, так як наш шаблон функції GetMax очікує два параметри того ж самого типу, і в цьому дзвінку в це ми використовуємо об'єкти двох різних типів.

Ми можемо також визначити шаблони функцій, які приймають більше ніж один параметр типу, просто вказуючи більше шаблонних параметрів між кутовими дужками. Наприклад:

template <class T, class U>

T GetMin (T a, U b) {

  return (a <b? a: b);

}

У цьому випадку наш шаблон функції GetMin () приймає два параметри різних типів і повертає об'єкт того ж самого типу як перший параметр (T), який передають. Наприклад, після того оголошення ми могли викликати GetMin () з:

int j;

long l;

i = GetMin <int,long> (j, l);

або просто:

i = GetMin (j, l);

навіть при тому, що у j і l є різні типи, так як компілятор може визначити адекватне інстанцірованія так чи інакше.

Спеціалізація шаблонів функції

Якщо для деяких типів загальний шаблон не підходить так як не перевантажені відповідно функції і т.д. потрібно визначити спеціалізацію шаблону:

Template<>

Char *min (char *a, char *b, char *c)

{

Int i;

i=cmpstr(a,b)

if (i<0)

{

i=cmpstr (b,c)

if (i<0)

return c;

else

return b;

}

else

{

i= cmpstr (a,b);

return i<0? c:a

}

}

ДРУЗІ КЛАСУ

Іноді виникає необхідність, щоб якась функція, що не є членом класу мала доступ до закритих та захищених полів об'єктів даного класу. У С++ є така можливість. Для цього необхідно і достатньо оголосити дану функцію другом цього класу. Зробити це можна за допомогою ключового слова “friend”. class friend_prob

{

private:

int status;

public:

int get_status(){return status;}

void set_status(int x){ status=x; return;}

//функція prob_friend оголошується другом класу

void friend prob_friend(friend_prob &obj );

};

void prob_friend( friend_prob &obj)

{

//функція друг здійснює доступ до закритого члена

//класу шляхом прямого звертання.

obj.status++;

return;

}

У даному прикладі функція prob_friend (friend_prob &obj) описана, як друг класу friend_prob. Це дозволяє їй дістати доступ до закритого поля даного класу status. Зверніть увагу на те, що, оскільки в програмі може існувати одночасно декілька об'ектів даного класу, такій функції необхідно як параметр передавати покажчик на об'єкт, з яким вона повинна працювати в даний момент.

21. ШАБЛОНИ КЛАСІВ

Досить часто при використанні ООП виникає необхідність введення великої кількості класів, які виконують однакові дії і відрізняються лише типами даних, по відношенню до яких ці дії застосовуються. Для спрощення виконання цієї задачі в С++ передбачені шаблони класів[5]. Шаблони класів це елементи мови програмування, які дозволяють визначити структуру сімейства класів, за якою компілятор самостійно створює потрібні класи, грунтуючись на параметрах настройки, що задаються. Цей механізм аналогічний механізму шаблонів функцій.

Найбільш типовий приклад використання шаблонів класів – це створення контейнерних класів, наприклад, векторів для розміщення об'єктів довільних типів.

Приклад:

template <class T>//шаблон класу вектор

class Vector

{

private:

T *elements;

int size;

public:

Vector(int razm=0); //конструктор, його реалізація має особливості

//деструктор, його реалізація також може мати особливості

~Vector(){delete elements;}

//перевантажений оператор для класу

T& operator[](int i){return elements[i];}//перевантажений оператор-метод

//метод, його реалізація має особливості

void print_contents();

};

//конструктор, його реалізація має особливості

template <class T>

Vector<T>::Vector(int razm)

{

elements=new T[razm];

for(int i=0; i< razm; elements[i]=(T) 0 i++);

size=razm;

};

//метод, реалізація якого має особливості

template <class T>

void Vector<T>::print_contents()

{

cout << "elements num-"<<size<<"\n";

for(int i=0; i<size; i++)

cout <<"el["<<i<<"]="<<elements[i] <<"\n";

}

//головна функція

//зверніть увагу на визначення типу для кожного об’єкту

int main()

{

int razmer=10;

Vector <int> i(razmer);

Vector <float> x(razmer);

Vector <char> з(razmer);

return 0;

}

Зверніть увагу на те, що заголовок шаблону класу починається з ключового слова template і містить вказівку на те, що тип наперед невідомий і повинен вказуватись при об’вленні об’єкту <class T>. Замість літери Т може бути використана інша літера. Головне, щоб у всіх методах і полях класу, де буде оброблюватись інформація даного типу стояла та ж сама літера. Це дасть змогу компілятору правильно сформувати об’єкт класу для заданого типу. При розробці шаблонів класів часто виникає проблема перевантаження операторів. Це пов’язано з тим, що з одного боку для розроблених програмістом класів, як правило, немає стандартних операторів, а з іншого боку дуже зручно, коли аналогічні операції для різних типів позначаються у програмі однаковими операторами.

22. ШАБЛОНИ КЛАСІВ

Досить часто при використанні ООП виникає необхідність введення великої кількості класів, які виконують однакові дії і відрізняються лише типами даних, по відношенню до яких ці дії застосовуються. Для спрощення виконання цієї задачі в С++ передбачені шаблони класів[5]. Шаблони класів це елементи мови програмування, які дозволяють визначити структуру сімейства класів, за якою компілятор самостійно створює потрібні класи, грунтуючись на параметрах настройки, що задаються. Цей механізм аналогічний механізму шаблонів функцій.

Найбільш типовий приклад використання шаблонів класів – це створення контейнерних класів, наприклад, векторів для розміщення об'єктів довільних типів.

Приклад:

template <class T>//шаблон класу вектор

class Vector

{

private:

T *elements;

int size;

public:

Vector(int razm=0); //конструктор, його реалізація має особливості

//деструктор, його реалізація також може мати особливості

~Vector(){delete elements;}

//перевантажений оператор для класу

T& operator[](int i){return elements[i];}//перевантажений оператор-метод

//метод, його реалізація має особливості

void print_contents();

};

//конструктор, його реалізація має особливості

template <class T>

Vector<T>::Vector(int razm)

{

elements=new T[razm];

for(int i=0; i< razm; elements[i]=(T) 0 i++);

size=razm;

};

//метод, реалізація якого має особливості

template <class T>

void Vector<T>::print_contents()

{

cout << "elements num-"<<size<<"\n";

for(int i=0; i<size; i++)

cout <<"el["<<i<<"]="<<elements[i] <<"\n";

}

//головна функція

//зверніть увагу на визначення типу для кожного об’єкту

int main()

{

int razmer=10;

Vector <int> i(razmer);

Vector <float> x(razmer);

Vector <char> з(razmer);

return 0;

}

Зверніть увагу на те, що заголовок шаблону класу починається з ключового слова template і містить вказівку на те, що тип наперед невідомий і повинен вказуватись при об’вленні об’єкту <class T>. Замість літери Т може бути використана інша літера. Головне, щоб у всіх методах і полях класу, де буде оброблюватись інформація даного типу стояла та ж сама літера. Це дасть змогу компілятору правильно сформувати об’єкт класу для заданого типу. При розробці шаблонів класів часто виникає проблема перевантаження операторів. Це пов’язано з тим, що з одного боку для розроблених програмістом класів, як правило, немає стандартних операторів, а з іншого боку дуже зручно, коли аналогічні операції для різних типів позначаються у програмі однаковими операторами.

ДРУЗІ КЛАСУ

Іноді виникає необхідність, щоб якась функція, що не є членом класу мала доступ до закритих та захищених полів об'єктів даного класу. У С++ є така можливість. Для цього необхідно і достатньо оголосити дану функцію другом цього класу. Зробити це можна за допомогою ключового слова “friend”. class friend_prob

{

private:

int status;

public:

int get_status(){return status;}

void set_status(int x){ status=x; return;}

//функція prob_friend оголошується другом класу

void friend prob_friend(friend_prob &obj );

};

void prob_friend( friend_prob &obj)

{

//функція друг здійснює доступ до закритого члена

//класу шляхом прямого звертання.

obj.status++;

return;

}

У даному прикладі функція prob_friend (friend_prob &obj) описана, як друг класу friend_prob. Це дозволяє їй дістати доступ до закритого поля даного класу status. Зверніть увагу на те, що, оскільки в програмі може існувати одночасно декілька об'ектів даного класу, такій функції необхідно як параметр передавати покажчик на об'єкт, з яким вона повинна працювати в даний момент.

23. У мові програмування C + + термін Стандартна Бібліотека означає колекцію класів і функцій , написаних на базовому мовою . Стандартна Бібліотека підтримує кілька основних контейнерів, функцій для роботи з цими контейнерами, об'єктів-функції, основних типів рядків і потоків (включаючи інтерактивний і файловий ввід-висновок), підтримку деяких мовних особливостей, і часто використовувані функції для виконання таких завдань, як, наприклад , знаходженняквадратногокореня числа. Стандартна Бібліотека мови C + + також включає в себе специфікації стандарту ISO C90 стандартної бібліотеки мови Сі . Функціональні особливості Стандартної Бібліотеки оголошуються всередині простору іменstd.

Стандартна бібліотека шаблонів (STL) - підмножина стандартної бібліотеки C + + і містить контейнери, алгоритми, ітератори, об'єкти-функції і т. д. [джерело не вказано 1197 днів] Хоча деякі програмісти використовують термін «STL» замість (або поперемінно) з терміном « Стандартна бібліотека C + + ».

Заголовки стандартної бібліотеки C + + не мають розширення «. H».

У стандартній бібліотеці C + + - останні розширення C + + стандарту ANSI (включаючи бібліотеку стандартних шаблонів і нову бібліотеку iostream). Вона являє собою набір файлів заголовків. У нових файлах заголовків відсутня розширення H.