на тему рефераты Информационно-образоательный портал
Рефераты, курсовые, дипломы, научные работы,
на тему рефераты
на тему рефераты
МЕНЮ|
на тему рефераты
поиск
Розробка власного класу STRING
/i>Warning FIG7_1. CPP: Non-const function

Time:: setHour (int) called for const object Warning FXG7 l. CPP: Non-const function

Time:: setMinute (int) callers for const object Warning FIG7 1. CPP: Non-const function

Time:: setSecond (int) called for const object

Мал.4. Використання класу Time з константними об'єктами й константними функціями-елементами

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

Константный об'єкт не може бути змінений за допомогою присвоювання, так що він повинен мати початкове значення. Якщо дані-елементи класу об'явлені як const, то треба використати ініціалізатор елементів, щоб забезпечити конструктор об'єкта цього класу початковими значенням даних-елементів. Мал.7 демонструє використання ініціалізатора елементів для завдання початкового значення константному елементу increment класу Increment. Конструктор для Increment змінюється в такий спосіб:

Increment:: Increment (int c, int i): increment (i) { count = c; }

Запис: increment (i) викликає завдання початкового значення елемента increment, рівного i. Якщо необхідно задати початкові значення відразу декільком елементам, просто включіть їх у список після двокрапки, розділяючи комами. Використовуючи ініціатори елементів, можна присвоїти початкові значення всім даним-елементам.

// Використання ініціалізатора елементів для

// ініціалізації даних константного вбудованого типу.

#include <iostream. h>

class Increment { public:

Increment (int з = 0, int i = 1);

void addlncrement () { count += increment; }

void print () const;

private:

int count;

const int increment; // константний елемент даних };

// Конструктор класу Increment Increment:: Increment (int c, int i)

: increment (i) // ініціали затор константного елемента

{ count = с; }

// друк даних

void Increment:: print () const

{

cout << "count = " << count

"", increment = " " increment << endl; }

main ()

{

Increment value (10,5);

cout << "Перед збільшенням: "; value. print ();

for (int j = 1; j <= 3;) }

value. addlncrement ();

cout << "Після збільшення " << j "": "; value. print ();

}

return 0; }

Перед збільшенням: count = 10, increment = 5

Після збільшення 1: count = 15, increment = 5

Після збільшення 2: count = 20, increment = 5

Після збільшення 3: count = 25, increment = 5

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

1.13 Друзі

Нехай визначені два класи: vector (вектор) і matrix (матриця). Кожний з них приховує своє подання даних, але дає повний набір операцій для роботи з об'єктами його типу. Допустимо, треба визначити функцію, що множить матрицю на вектор. Для простоти припустимо, що вектор має чотири елементи з індексами від 0 до 3, а в матриці чотири вектори теж з індексами від 0 до 3. Доступ до елементів вектора забезпечується функцією elem (), і аналогічна функція є для матриці. Можна визначити глобальну функцію multiply (помножити) у такий спосіб:

vector multiply (const matrix& m, const vector& v);

{

vector r;

for (int i = 0; i<3; i++) { // r [i] = m [i] * v;

r. elem (i) = 0;

for (int j = 0; j<3; j++)

r. elem (i) +=m. elem (i,j) * v. elem (j);

}

return r;

}

Це цілком природнє рішення, але воно може виявитися дуже неефективним. При кожному виклику multiply () функція elem () буде викликатися 4* (1+4*3) раз. Якщо в elem () проводиться контроль границь масиву, то на такий контроль буде витрачено значно більше часу, ніж на виконання самої функції, і в результаті вона виявиться непридатної для користувачів. З іншого боку, якщо elem () є якийсь спеціальний варіант доступу без контролю, то тим самим ми засмічуємо інтерфейс із вектором і матрицею особливою функцією доступу, що потрібна тільки для обходу контролю.

Якщо можна було б зробити multiply членом обох класів vector і matrix, ми могли б обійтися без контролю індексу при звертанні до елемента матриці, але в той же час не вводити спеціальної функції elem (). Однак, функція не може бути членом двох класів. Треба мати в мові можливість надавати функції, що не є членом, право доступу до приватних членів класу. Функція - не член класу, але має доступ до його закритої частини, називається другом цього класу. Функція може стати другом класу, якщо в його описі вона описана як friend (друг). Наприклад:

class matrix;

class vector {

float v [4];

// ...

friend vector multiply (const matrix&, const vector&);

};

class matrix {

vector v [4];

// ...

friend vector multiply (const matrix&, const vector&);

};

Функція-друг не має ніяких особливостей, за винятком права доступу до закритої частини класу. Зокрема, у такій функції не можна використати вказівник this, якщо тільки вона дійсно не є членом класу. Опис friend є дійсним описом. Воно вводить ім'я функції в область видимості класу, у якому вона була описана, і при цьому відбуваються звичайні перевірки на наявність інших описів такого ж імені в цій області видимості. Опис friend може перебуває як у загальній, так і в приватній частинах класу, це не має значення.

Тепер можна написати функцію multiply, використовуючи елементи вектора й матриці безпосередньо:

vector multiply (const matrix& m, const vector& v)

{

vector r;

for (int i = 0; i<3; i++) { // r [i] = m [i] * v;

r. v [i] = 0;

for (int j = 0; j<3; j++)

r. v [i] +=m. v [i] [j] * v. v [j];

}

return r;

}

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

Функція-член одного класу може бути другом іншого класу:

class x {

// ...

void f ();

};

class y {

// ...

friend void x:: f ();

};

Цілком можливо, що всі функції одного класу є друзями іншого класу. Для цього є коротка форма запису:

class x {

friend class y;

// ...

};

У результаті такого опису всі функції-члени y стають друзями класу x.

1.14 Ядро ООП: Успадкування та поліморфізм

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

1.4.1 Похідні класи

Обговоримо, як написати програму обліку службовців деякої фірми
. У ній може використатися, наприклад, така структура даних:

struct employee { // службовець

char* name; // ім'я

short age; // вік

short department; // відділ

int salary; // оклад

employee* next;

// ...

};

Поле next потрібно для зв'язування в список записів про службовців одного відділу (employee). Тепер спробуємо визначити структуру даних для керуючого (manager):

struct manager {

employee emp; // запис employee для керуючого

employee* group; // підлеглий колектив

short level;

// ...

};

Керуючий також є службовцем, тому запис employee зберігається в члені emp об'єкта manager. Для людини ця спільність очевидна, але для транслятора член emp нічим не відрізняється від інших членів класу. Вказівник на структуру manager (manager*) не є вказівником на employee (employee*), тому не можна вільно використати один замість іншого. Зокрема, без спеціальних дій не можна об'єкт manager включити до списку об'єктів типу employee. Доведеться або використати явне приведення типу manager*, або в список записів employee включити адресу члена emp. Обоє рішень некрасиві й можуть бути досить заплутаними. Правильне рішення полягає в тому, щоб тип manager був типом employee з деякою додатковою інформацією:

struct manager: employee {

employee* group;

short level;

// ...

};

Клас manager є похідним від employee, і, навпаки, employee є базовим класом для manager. Крім члена group у класі manager є члени класу employee (name, age і т.д.). Графічно відношення спадкування звичайно зображується у вигляді стрілки від похідних класів до базового:

employee

manager

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

Маючи визначення employee і manager, можна створити список службовців, частина з яких є й керуючими:

void f ()

{

manager m1, m2;

employee e1, e2;

employee* elist;

elist = &m1; // помістити m1 в elist

m1. next = &e1; // помістити e1 в elist

e1. next = &m2; // помістити m2 в elist

m2. next = &e2; // помістити m2 в elist

e2. next = 0; // кінець списку

}

Оскільки керуючий є також службовцем, вказівник manager* можна використати як employee*. У той же час службовець не обов'язково є керуючим, і тому employee* не можна використати як manager*.

У загальному випадку, якщо клас derived має загальний базовий клас base, то вказівник на derived можна без явних перетворень типу привласнювати змінній, що має тип вказівника на base. Зворотне перетворення від вказівника на base до вказівника на derived може бути тільки явним:

void g ()

{

manager mm;

employee* pe = &mm; // нормально

employee ee;

manager* pm = &ee; // помилка:

// не всякий службовець є керуючим

pm->level = 2; // катастрофа: при розміщенні ee

// пам'ять для члена 'level' не виділялася

pm = (manager*) pe; // нормально: насправді pe

// не настроєно на об'єкт mm типу manager

Страницы: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15



© 2003-2013
Рефераты бесплатно, курсовые, рефераты биология, большая бибилиотека рефератов, дипломы, научные работы, рефераты право, рефераты, рефераты скачать, рефераты литература, курсовые работы, реферат, доклады, рефераты медицина, рефераты на тему, сочинения, реферат бесплатно, рефераты авиация, рефераты психология, рефераты математика, рефераты кулинария, рефераты логистика, рефераты анатомия, рефераты маркетинг, рефераты релиния, рефераты социология, рефераты менеджемент.