Поможем написать учебную работу
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.
PAGE 8
FILENAME Лекція №3 Функції-члени класу.doc
[1] Конструктори і деструктори [2] Правила для конструкторів [3] Правила для деструкторів [4] Список ініціалізації елементів [5] Конструктори за замовчуванням [6] Конструктори копіювання [7] Покажчик this [8] Статичні дані- члени класу [9] Статичні функції - члени класу [10] Константні дані - члени класу [11] Константні функції - члени класу [12] Константні об'єкти |
Створюючи деякий об'єкт, його необхідно проініціалізувати. Для цієї мети C++ надає функцію-член, яка називається конструктором.
Програміст не повинен писати код, що викликає конструктор класу. Усю необхідну роботу виконує компілятор. Функцією членом, що виконує дії, зворотні конструкторові, є деструктор.
Програміст не повинен писати код, що викликає деструктор класу. Усю необхідну роботу виконує компілятор. Деструктор класу викликається в момент видалення об'єкта.
class Dot
{
public :
Dot ( ) { cout <<"Constructor \n"; } // конструктор
~dot ( ) { cout <<"Destructor \n"; } // деструктор
}
void main ( )
{
Dot A ; // створення об'єкта
}
Результат:
Constructor
Destructor
Якщо потрібно проініціалізувати змінні класу, використовується конструктор з параметрами.
class Dot
{
char name ; // ім'я крапки
double x, y ; // координати крапки
public:
Dot ( char Name, double X, double Y ) { name = Name ; x = X ; y = Y ; }
void Print ( ) ;
}
void Dot :: Print()
{
cout<<”koord point”<<name<<" :";
cout<<"\tx="<<x<<"\ty="<<y<<'\n';
}
void main ( )
{
Dot A ( 'A', 3, 4 ) ; // неявний виклик конструктора
Dot В= Dot ('В', 3, 4 ) ; // явний виклик конструктора
A.Print ( ) ; // виклик функції члена класу
}
Тут значення, передане в конструктор при оголошенні об'єкта A, використовується для ініціалізації закритих членів name, x і y цього об'єкта.
Звичайно дані-члени класу ініціалізуються в тілі конструктора, однак існує й інший спосіб ініціалізації за допомогою списку ініціалізації елементів. Список ініціалізації елементів відділяється двокрапкою від заголовка визначення конструктора й містить дані - члени й конструктори базових класів, розділені комами. Для кожного елемента в круглих дужках безпосередньо за ним вказується один або кілька параметрів, використовуваних при ініціалізації. Синтаксис списку ініціалізації має вигляд:
Constrname ( parl, par2 ) : mem1 ( parl ), mem2 ( par2 ), … { …}
class Dot
{
char name ;
double x, y ;
public:
Dot ( char Name ) : name ( Name ), x ( 0 ), y ( 0 ) { }/
• • •
} ;
Хоча виконання ініціалізації в тілі конструктора або за допомогою списку ініціалізації справа смаку програміста, список ініціалізації є єдиним методом ініціалізації для:
C++ визначає два спеціальні види конструкторів: конструктор за замовчуванням і конструктор копіювання.
Конструктором за замовчуванням є конструктор, використовуваний для побудови об'єкта, коли явні значення для ініціалізації відсутні. Для класу Point це
Point PP;
Тоді конструктор за замовчуванням виглядає так:
Point(){}
Другий варіант завдання конструктора за замовчуванням це завдання значень за замовчуванням для всіх параметрів.
Point(char Nam=A', int X=0,int Y=0){name=Nam;x=X;y=Y;}
Таким чином, конструктор за замовчуванням не має параметрів (або всі його параметри повинні мати значення за замовчуванням) і викликається при створенні об'єкта, якому не задані аргументи. Слід уникати двозначності при виклику конструкторів. Одночасне використання цих конструкторів неприпустимо, тому що з'являється двозначність:
Point pp1(B'); -використовується другий конструктор
Point pp1; використовується або перший або другий з усіма параметрами за замовчуванням.
У цьому випадку, щоб усунути неоднозначність, досить вилучити з оголошення класу конструктор без параметрів.
При явному виклику конструктора за замовчуванням дужки не ставляться.
Ще раз конструктор за замовчуванням створюється автоматично тільки якщо не визначений жоден конструктор класу, інакше помилка.
Конструктор копіювання створює об'єкт класу, копіюючи при цьому дані із уже існуючого об'єкта даного класу. Тому він повинен мати в якості єдиного параметра константне посилання на об'єкт класу ( const Т& ) або просто посилання на об'єкт класу ( Т&)Використання першого переважніше, тому що останній не дозволяє копіювати константні об'єкти.
Посилання передається щораз, коли новий об'єкт ініціалізуються значеннями існуючого об'єкта. Якщо ви не передбачили конструктор копіювання, компілятор генерує конструктор копіювання за замовчуванням.
В C++ розрізняють поверхневе й глибинне копіювання даних.
При поверхневім копіюванні відбувається почленне копіювання. При наявності в об'єкта членів, що є покажчиками, отримана копія об'єкта, швидше за все, буде непридатною. Конструктор копіювання за замовчуванням, створений компілятором здійснює поверхневе копіювання.
У випадку глибинного копіювання відбувається дійсне копіювання значень усіх змінних з однієї області пам'яті в іншу. Тому для класів, що містять покажчики й посилання, треба:
Якщо в класі не визначений конструктор копіювання, компілятор намагається згенерувати, якщо потрібно, власний конструктор копіювання.
class Dot
{
char name ;
double x, y ;
public:
// конструктори з параметрами
Dot ( char Name, double X, double Y) { name = Name ; x = X ; y = Y ; }
Dot ( char Name) : name( Name ), x ( 0 ), y ( 0 ) { }
Dot ( char Name, const Dot& A ) { name = Name ; x = A.x ; y = A.y ; }
// конструктор копіювання
Dot ( const Dot& A ) { name = ( char ) 226 ; x = A.x ; y = A.y ; }
void Print ( ) ;
};
void Print ( )
{cout<<”x=”;}
void main ( )
{
Dot A ('A', 3, 4 ) ; // виклик конструктора Dot ( char Name, double X, double Y )
Dot B ('B') ; // виклик конструктора Dot ( char Name )
!! Dot C ( A ) ; // виклик конструктора копіювання Dot ( const Dot& A )
C.Print ( ) ;
!! Dot D = B ; // виклик конструктора копіювання Dot ( const Dot& A )
D.Print ( ) ;
Dot E ('E', A ) ; // виклик конструктора Dot ( char Name, const Dot& )
E.Print ( ) ; // виводить на екран: Координати крапки E: x=3 y=4
}
У наведеному прикладі крапки C і D оголошені за допомогою конструктора копіювання, де ім'я крапки ініціалізуються фіксованим значенням російською буквою “т”.
Конструктор:
Dot ( char Name, const Dot& A ) { name = Name ; x = A.x ; y = A.y ; },
у якості параметрів приймає ім'я й крапку, координати якої використовуються для ініціалізації.
Кожний об'єкт в C++ містить спеціальний покажчик з іменем this, який автоматично створюється самим компілятором і вказує на поточний об'єкт. Типом this є Т*, де Т тип класу поточного об'єкта. Оскільки покажчик this визначений у класі, область його дії клас, у якім він визначений. Дружнім функціям і статичним функціям-членам класу покажчик this не передається.
// функція повертає крапку - середину відрізка, кінці якого задані
Dot& Dot :: Middle ( Dot A, Dot B )
{
x = ( A.x + B.x ) / 2.0 ; y = ( A.y + B.y ) / 2.0 ;// обчислює середину відрізка
Print ( ) ; // виводить на екран координати поточної крапки
this -> Print ( ) ; // усі три оператори еквівалентні
(*this) . Print ( ) ;
return *this ; // повертає посилання на поточну точку
}
Виклик функцій може здійснюватися як безпосередньо по імені, так і за допомогою покажчика this. На практиці таке вживання покажчика this зустрічається вкрай рідко. В основному покажчик this використовується для повернення покажчика ( у формі: return this ;) або посилання ( у формі: return *this ;) на відповідний об'єкт. Цей покажчик знаходить широке застосування при перевантаженні операторів.
Члени класу можуть бути оголошені з модифікатором static. Дане-член класу, визначене з модифікатором static, розділяється всіма представниками цього класу; існує тільки один екземпляр цієї змінної.
Пам'ять під статичні дані-члени виділяється, навіть якщо немає ніяких представників класу. Тому клас повинен не тільки повідомляти статичні дані-члени, але й визначати їх. До статичних даних-членам, оголошеним у розділі public класу, рекомендується звертатися за допомогою наступної конструкції:
<ім'я_класу> :: <дане_член>
Ця форма звертання відображає той факт, що відповідне дане-член є єдиним для всього класу.
Якщо статичні дані-члени оголошені як закриті, то доступ до них можна одержати за допомогою звичайних функцій - членів. Доступ до статичних даних-членам за допомогою звичайних функцій членів нічим не відрізняється від доступу до інших даних-членам, але для цього необхідно створити хоча б один об'єкт даного класу. У зв'язку зі сказаним вище, можна дати наступні рекомендації:
застосовуйте статично дані - члени для спільного використання даних декількома об'єктами класу;
обмежте доступ до статичних даних-членам, оголосивши їх у розділі protected або private.
Розглянемо приклад використання статичного даного члена класу:
#include<iostream>
#include<windows.h>
using namespace std;
class Dot
{
static int count;
// оголошення статичного даного члена лічильника об'єктів
public: // відкриті члени класу
Dot ( char Name )
{ name = Name x = 0; y = 0 ; count ++ ; } //збільшення лічильника об'єкта на 1
~dot ( ) { count -- ; }// деструктор зменшує лічильник об'єктів на 1
void Printcount ( ) ; // функція виводить кіл існуючих об'єктів
} ;
Файл Dot.cpp
#include "Dot.h" // підключення заголовного файлу класу Dot
void Dot :: Printcount ( )
{
char S [ 30 ] ;
cout<<"У пам'яті існує "<<count <<" об'єкта типу Dot\n";
}
Файл Main.cpp
#include "Dot.h" // підключення заголовного файлу класу Dot
int Dot :: count = 0 ; // ініціалізація статичного даного-члена
void main ( )
{
Dot A ('A'), B ( B'), C ( C') ; // виклик конструктора Dot ( char Name )
A.Printcount ( ) ;
cout<<Dot :: count<< '\n' ; // помилка: дане-член count недоступний
}
У цьому прикладі статичне дане-член count містить кількість існуючих об'єктів. Ініціалізація даного-члена count здійснюється перед виконанням програми й створенням об'єктів у файлі основної програми за допомогою оператора:
void Dot :: count=0;
Зверніть увагу, що звертання до цього члена класу у функції main ( ) в операторові
cout<<Dot :: count<< '\n' ;
приводить до помилки, оскільки дане-член класу count оголошене як закрите і є недоступним за межами класу.
При виконанні програма виводить на екран:
У пам'яті існує 3 об'єкта типу Dot
Коректний облік кількості існуючих об'єктів досягається двома діями: кожний конструктор, ( у тому числі й конструктор копіювання) збільшує лічильник на одиницю, деструктор зменшує на одиницю. Оскільки конструктор викликається при створенні кожного об'єкта, а деструктор при знищенні, то дане-член count буде містити кількість існуючих об'єктів незалежно від того яким образом і в якій області визначення створений або знищений об'єкт.
Особливістю використання статичних функцій-членів є те, що вони також визначені в єдиному екземплярі й не є безроздільною власністю якогось представника класу.
У зв'язку із цим їм не передається покажчик this. Ця особливість статичних функцій-членів використовується при написанні функцій-оброблювачів переривань і callback-функцій ( при програмуванні для Windows).
Зі сказаного вище випливає кілька важливих наслідків:
статична функція-член може викликатися незалежно від того, існує чи ні який-небудь представник класу;
статична функція-член може маніпулювати тільки статичними даними-членами класу й викликати тільки інші статичні функції-члени класу;
статична функція-член не може бути оголошена з модифікатором virtual.
Данні-члени класу може бути оголошений з модифікатором const, який указують перед типом константного даного. Ключове слово const інформує компілятор, що значення даного елемента об'єкта не повинне змінюватися після ініціалізації. Константні дані-члени класу не можна ініціалізувать у конструкторові звичайним образом. Список ініціалізації є єдиним методом ініціалізації даних-констант. Приведемо приклад оголошення константного даного і його ініціалізації:
class Dot
{
const char name ; // ім'я крапки константне дане-член
double x, y ; // координати крапки
public: // відкриті члени класу
Dot ( char Name, double X, double Y ) : name ( Name ), x ( X ), y ( Y ) { }
Dot ( char Name) : name ( Name ), x ( 0 ), y ( 0 ) { }
} ;
Функція-член класу може бути оголошена з модифікатором const, який іде за списком параметрів. Така функція не може змінювати значення даних-членів класу й не може викликати не константні функції-члени класу. Приведемо приклад оголошення константної функції-члена класу:
class Coord
{
double x, y ; // координати
public : // відкриті члени класу
Coord ( ) { x = 0 ; y = 0 ; } // ініціалізує координати нулями
double Getx ( ) const { return x ; } // константна функція повертає коорд x
double Gety ( ) const { return y ; } // константна функція повертає коорд y
void Setx ( double X ) { x = X ; } // встановлює задане знач коорд x
void Sety ( double Y ) { y = Y ; } // встановлює задане знач коорд у
} ;
Можна також створювати константні об'єкти. Для цього перед їхнім оголошенням ставлять модифікатор const. Наприклад,
const Coord A ( 3, 5 ) ;
Ключове слово const інформує компілятор, що стан даного об'єкта не повинен змінюватися. У зв'язку із цим компілятор генерує повідомлення про помилку, якщо для константного об'єкта викликається функція-член (яка може змінити його дані-члени, змінивши тим самим його стан). Виключенням із цього правила є константні функції-члени, які в силу свого визначення не змінюють стан об'єкта.