
- •Передмова
- •Розділ 1 об'єктний підхід у програмуванні
- •1.1.Причини виникнення ооп
- •1.1.1.Складність об'єкта дослідження
- •1.1.2.Складність процесу розробки програмного забезпечення
- •1.1.3.Складність опису окремих елементів
- •1.2.Парадигма ооп
- •1.3.Історія розвитку ооп
- •Розділ 2 об'єкти й класи: інкапсуляція
- •2.1.Структура об'єкта й класу
- •2.2.Особливості опису класів у мовах ооп
- •2.2.1.Опис класів в SmallTalk
- •2.2.3.Опис класів в Delphi
- •2.2.4.Опис класів в Java
- •2.3.Поля даних та їх ініціалізація
- •2.3.1.Визначення полів даних в SmallTalk
- •2.3.3.Визначення полів даних в Delphi
- •2.3.4.Визначення змінних в Java
- •2.4.Доступ до даних
- •2.4.1.Доступ до даних в SmallTalk
- •2.4.3.Доступ до даних в Delphi
- •2.4.4.Доступ до даних в Java
- •2.5.Спеціальні змінні
- •2.5.1.Спеціальні змінні в SmallTalk
- •2.5.3.Спеціальні змінні в Java
- •2.5.4.Спеціальні змінні в Delphi
- •2.6.Посилання
- •2.6.1.Визначення посилань в SmallTalk, Delphi і Java
- •2.7.Методи
- •2.7.1.Загальна схема визначення методу
- •2.7.2.Визначення методів в SmallTalk
- •2.7.4.Визначення методів в Delphi
- •2.7.5.Визначення методів в Java
- •2.8."Дружні" методи
- •2.8.2.Аналог дружніх функцій в Delphi
- •2.9.Конструктори й деструктори
- •2.9.1.Конструктори й деструктори в SmallTalk
- •2.9.3.Конструктори й деструктори в Delphi
- •2.9.4.Конструктори й деструктори в Java
- •2.10.Властивості
- •2.10.1.Властивості в Delphi
- •2.10.2.Властивості в Java
- •2.12.Абстрактні методи
- •Розділ 3 успадкування
- •3.1.Форми успадкування
- •3.2.Успадкування в SmallTalk
- •3.3.1.Віртуальне успадкування
- •3.3.2.Правило сумісності типів
- •3.3.3.Використання конструкторів і деструкторів при успадкуванні
- •3.4.Успадкування в Delphi
- •3.4.1.Ієрархія класів в Delphi
- •3.4.2.Створення нових компонентів
- •3.5.Успадкування в Java
- •3.5.1.Використання ключового слова super
- •3.5.2.Клас Object
- •Розділ 4 поліморфізм
- •4.1.Віртуальні методи
- •4.2.1.Механізм пізнього зв'язування
- •4.2.2.Таблиця віртуальних методів
- •4.3.Поліморфізм в Delphi
- •4.3.1.Заміщення віртуальних і динамічних методів
- •4.3.2.Приведення типів
- •4.4.Поліморфізм в Java
- •4.5.Поліморфізм в SmallTalk
- •5.1.Потокові класи
- •5.1.1.Ієрархія потокових класів
- •5.1.2.Форматоване введення/ виведення
- •5.1.3.Маніпулятори
- •5.1.4.Введення/виведення у файл
- •5.2.Контейнерні класи
- •5.2.1.Ітератори
- •5.2.2.Визначення контейнерних класів
- •5.2.3.Стандартні контейнерні класи
- •5.3.1.Параметиізовані класи (шаблони)
- •5.3.2.Ітератори stl
- •5.3.3.Узагальнені алгоритми
- •Література
- •Додатки лабораторна робота №1 об'єкти й повідомлення в smalltalk
- •Лабораторна робота №2 класи й методи в smalltalk
- •Листинг 3.1
- •Листинг 3.2
- •Листинг 3.3
- •Лабораторна робота 5 компоненти в delphi
- •Лабораторна робота 6 меню й вікна в delphi
- •Лабораторна робота 7 розробка меню в java
- •Лабораторна робота 8 робота з подіями в java
5.1.3.Маніпулятори
Це спеціальні функції для модифікації формату, які можна включати в оператори введення й виведення.
Нижче наведені найбільше часто використовувані маніпулятори:
setw(int) – аналогічно width(int);
setfill(int) – установлює символ-заповнювач;
ws – ігнорувати пробіли при введенні;
endl – вставка символу наприкінці рядка;
dec – виведення в десятичному форматі;
oct – виведення в восьмеричному форматі;
hex – виведення в шістнадцятерічному форматі;
flush – при виведенні вивантажує буфер.
Приклад використання маніпуляторів:
cout << setw(4) << i << setw(6) << j;
Це рівносильно:
cout.width(4);
cout << i;
cout.width(6);
cout << j;
Для використання маніпуляторів необхідно підключити до програми заголовочний файл <iomanip.h>.
5.1.4.Введення/виведення у файл
Відкриття файлу на введення/виведення здійснюється шляхом використання наступної конструкції:
fstream <ім'я об'єкта> (<шлях до файлу>, <список прапорів >);
Наприклад, це може виглядати так:
fstream inout ('c:\My\data.bat', ios::in | ios:out);
Прапори визначені в класі ios:
class ios {public:
enum open_mode {
in, // прапор введення
out, // прапор виведення
app, // додавання даних у кінець файлу
nocreate, //видається помилка, якщо файл не існує
noreplace // помилка, якщо не встановлений прапор app
};
};
Після відкриття файлу запис і зчитування відбувається за допомогою перевизначених операцій << і >>:
fstream inout(“c:\My\data”, ios::in|ios::out);
inout << i;
inout >> j;
Крім форматованого введення/виведення існують функції неформатованого введення/виведення:
put(char);
write(const unsigned char* ptr, int n);
Дані функції дозволяють вивести один символ і вивести n символів, відповідно:
cout.put('a'); // буде виведене “a”
cout.write(“Hello”,3); // буде виведене “Hel”
5.2.Контейнерні класи
Класи, які містять покажчики або об'єкти, що містять покажчики, називаються контейнерними. До них відносяться класи, які використовуються для побудови списків, стеків, черг, масивів, словників. Такі класи приховують подробиці об'єктів, що включають, і забезпечують зручні зовнішні способи реалізації операцій обробки перерахованих структур. У свою чергу, реалізація операцій з об'єктами контейнерних класів ґрунтується на можливості одержання доступу до їхніх окремих елементів. Одним зі шляхів вирішення цього завдання є створення спеціального класу, задача якого полягає у звертанні до елементів екземпляра контейнерного класу. Цей спеціальний клас повинен виконувати ітерації над елементами іншого класу.
5.2.1.Ітератори
Стандартним прийомом реалізації ітерації є використання оператора for:
for (i=0; i<size; i++)
sum+=a[i]; // підсумовування елементів
Масив, що використовує даний цикл, може бути описаний так:
class vect {
private:
int *p; // базовий покажчик
int size; // розмір масиву
int cur_ind; // поточний індекс
public:
vect (int); // конструктор
int & next(); // звертання до наступного елемента
} &а;
vect::vect(int n): cur_ind(0){
size = n;
p = new int[size];
}
int & vect :: next (){
if (cur_ind = = size)
return(p[cur_ind = 0]); //скидання індексу й повернення до 1-му елемента
esle
return(p[cur_ind ++]); // повернення елемента й збільшення індексу
}
void main (){
for (i = 0; i <= (size-1);++ i)
sum += a.next();
}
У даному прикладі індекс i вже розв'язаний зі зверненням до елемента, проте, побічно використовується індекс cur_ind класу vect. Це означає, що звертання до масиву обмежується використанням одного індексу (одного екземпляра вектора) під час різних обігів. Такий порядок аналогічний, наприклад, відвідуванню великого музею тільки одним екскурсантом.
У той же час об'єкт класу vect постійно існує в пам'яті й повинен бути здатний обслужити безліч звертань до нього. . Один зі способів забезпечити це - продублювати масив для кожного завдання, що вимагає звертання до елементів масиву (аналогічно тому. що дати кожному екскурсантові по музею). Інший шлях - створити безліч індексів і передавати їхнім функціям обігу, але це веде до різкого збільшення невиробничих витрат.
Оптимальне рішення складається в створенні окремого, пов'язаного з вихідним класом vect, класа-ітератора, у функції, якого буде входити стандартне звертання до елементів масиву. Із цією метою змінимо визначення класу vect:
class vect {
private:
friend class vect_iterator;
int *p;
public:
…………………
};
class vect_iterator {
private:
vect *pv; // зв'язаний об'єкт vect
int cur_ind; // поточний індекс
public:
vect_iterator (vect & v): cur_ind (0); {}
int & next();
};
int & vectiterator :: next (){
if (cur_ind = = pv > size)
return(pv > p [cur_ind = 0]);
esle
return(pv > p [cur_ind ++]);
}
Тепер у наявності повне від'єднання звертання до елемента від контейнерного екземпляра vect, і можна оголосити як завгодно багато ітераторів для всіх необхідних обчислень (оголошення ітератора рівносильне видачі дозволу ще одному екскурсантові відвідати музей, не залежно від того, скільки там людей уже перебуває).
Таким чином, використання контейнерних класів сполучено із застосуванням спеціальних класів-ітераторів.