МІНІСТЕРСТВО ОСВІТИ І НАУКИ, МОЛОДІ ТА СПОРТУ УКРАЇНИ
Національний університет “Львівська політехніка”
Кафедра САП
Звіт
до лабораторної роботи № 8
Особливості мови об’єктно-орiєнтованого програмування С++
з курсу “Проблемно-орієнтоване програмування”
для студентів спеціальності "Комп’ютерні системи проектування"
Львів 2013
ТЕОРЕТИЧНІ ВІДОМОСТІ
1. МЕТА РОБОТИ
Мета роботи - ознайомлення з особливостями мови об’єктно-орiєнтованого програмування С++.
2. ТЕОРЕТИЧНІ ВІДОМОСТІ
2.1. Основнi вiдмiнностi С++ вiд С
С++ - унiверсальна мова програмування, яка задумана так, щоб зробити програмування бiльш приємним для серйозного програмiста. С++ була розроблена так, щоб дати можливiсть однiй людинi без надмiрних зусиль написати програму в 2500 стрiчок.
За базову мову для С++ була вибрана мова С, тому що:
вона вiдносно низького рiвня.;
вiдповiдає бiльшостi задач системного програмування;
вже створено мiльони стрiчок бiблiотечних функцiй i сервiсних програм, написаних на С;
iснують сотнi тисяч програмiстiв, якi знають С.
До ключових слiв визначених в С у мову С++ додано такі ключовi слова:
overload
delete
friend
protected
catch
new
inline
public
try
this
operator
template
throw
class
private
virtual
Основна р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ддаються керуванню. Цi концепцiї називаються: об’єкти, полiморфiзм, успадкування. Розглянемо їх детальніше.
Об’єкти
Об’єкт це логiчна одиниця, яка мiстить данi i код, що манiпулює цими даними. Всерединi об’єкту, код i/або данi можуть належати тільки даному об’єкту i недосяжнi будь-де за межами об’єкту. Таким чином об’єкт забезпечує певний рiвень захищеностi вiд iншої частини програми, що може випадково змiнити або некоректно використати цi данi.
Об’єкт - це змiнна визначена самим користувачем. Коли ви визначаєте об’єкт ви неявно створюєте новий тип даних.
Інкапсуляція
Інкапсуляція (incapsulation) – це механізм, який зв’язує воєдино код і дані, якими він управляє, а також забезпечує їхній захист від зовнішнього або неправильного використання. Всередині об’єкту код (функція) і дані можуть бути закритими (private) або відкритими (public). До закритої частини коду або даних не можна доступитись зовні, відкриті код або дані доступні з довільної частини програми. Як правило, відкрита частина коду забезпечує керовану взаємодію (інтерфейс) із закритими елементами об’єкта.
Полiморфiзм
ООП пiдтримує полiморфiзм який означає що одне iм’я може бути використане для декiлькох зв’язаних, але дещо рiзних застосувань. Наприклад, ви можете мати програму, що визначає три рiзних типи стека. Один стек застосовується для типу integer, iнший для float а наступний для long. Завдяки полiморфiзму ви створюєте функцiї роботи з елементами стеку, наприклад, push(), pop(), а компiлятор сам вибере потрiбну функцiю в залежностi вiд типу виклику.
Поліформізм дозволяє спростити програму, створюючи один інтерфейс для виконання різних дій. Відповідальність за вибір конкретної дії (методу) і ситуації, яка при цьому виникає, покладається на компілятор. Програмісту не обов’язково вникати в цей процес. Необхідно лише пам’ятати відповідні правила, і коректно застосовувати загальний інтерфейс.
Успадкування
Успадкування (inheritance) – це процес, впродовж якого один обєкт може набувати властивості іншого. Він займає авжливе місце в С++, оскільки підтримує концепцію класифікації (classification).
За допомогою успадкування програмiст може виразити iєрархiчну класифiкацiю. Наприклад принтер “Epson LX 1050” є частиною матричних принтер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дносно легко вносити змiни у програму. Це також зменшує кiлькiсть помилок, а отже i вартiсть програмного забезпечення, але водночас мова С++ не звiльняє програмiста вiд кодування i алгоритмiв.
Коротко про деякі технічні відмінності у мовах С++ і ANSI C:
Операція розширення області видимості (::)
В межах класу заміняє глобальні змінні та глобальні функції.
Посилання (&)
Бiблiотечнi функцiї malloc i free є стандартними С - функцiями, які використовують для видiлення i вивiльнення пам’ятi. Робота з пам’ятю в С++ набагато гнучкiша. Два оператора new i delete забезпечують роботу з пам’ятю. Вони автоматично викликаються при створеннi, знищеннi і копіюванні об’єкта без участi програмiста, при умові їх визначення.
Зникла необхiднiсть у препроцесорi #define, його з успiхом замiняють inline пiдстановки, та const.
Довжина змінних в С може бути до 32 знаків, в С++ на довжину не має обмежень.
Приведення до явного типу в С++ у визначених типів може відбуватися двояко. Наприклад:
(float) t;
float (t);
В ANSI С оголошення функцiї funct(void), визначає що виклик функцiї вiдбувається без аргументiв. Це допустимо для С++, але ключове слово void можна опустити без втрати змiсту виклику.
В С++ при оголошенннi функцiй написаних на мовi С, додається надпис extern “C”. Наприклад
extern “C” puts(const char* s);
main()
{ puts(“hello, world”); }
В С++ на відміну від С існує виклик функцій по замовчуванню:
Змінні в С++ можуть оголошуватись будь-де в програмі
Робота з потоками.
Мова С++ не забезпечує засоби для вводу/виводу. Цього їй і не потрібно: такі засоби легко і елегантно можна створити з допомогою самої мови.
Традиційно засоби вводу/виводу розроблялися для невеликого числа вбудованих типів даних. Але, в програмах на С++ як правило використовуються багато типів даних, визначених користувачем і тому потрібно також обробляти ввід і вивід значень цих типів. Очевидно, що засоби вводу/виводу повинні бути простими, зручними, надійними в керуванні, ефективними і гнучкими і до всього іншого повними.
С++ містить декілька визначених потоків, що автоматично відкриваються коли починається виконання С++ програми. Це стандартний ввід (cin), стандартний вивід (cout), вивід помилки (cerr).
Форматування
Деколи виникає необхідність регулювати вивід тексту. Функція width() вказує мінімальне число символів, які будуть використані наступною операцією виводу числового значення або символьної стрічки.
Символ-заповнювач можна задати функцією fill().
Виклик функції width впливає тільки на операцію виводу, яка виконується безпосередньо за нею, так що в результаті отримується
cout << 1234.56789 << ‘\n’;
cout.setf (ios::scientific, ios::floatfield);
cout << 1234.56789 << ‘\n’;
cout.setf (ios::fixed, ios::floatfield);
cout <<1234.56789 << ‘\n’;
отримаємо 234.57
1.2345678e+03
1234.567890
В результаті звертання до функції cout.precision(n) буде встановлене значення по замовчуванню для числа цифр, що друкуються, яке рівне n. Виклик функції precision впливає на всі наступні операції вводу/виводу до наступного виклику precision.
Відкривання і закривання файлів
В С++ реалізуються три типи потоків для роботи з файлами.
ifstream in; відкривання файла для читання
ofstream out; відкривання файла для запису
fstream both; відкривання файла для читання і запису
Якщо ви відкрили потік, єдиний шлях зв’язати потік з файлом реалізується функцією open(), яка є членом кожного з трьох класів, які реалізують ці потоки. Прототип цієї функції:
void open (char *filename, int mode, int access)
filename – ім’я файлу
mode - спосіб відкриття файлу
ios::app //додати
ios::ate //відкрити і шукати кінець файлу
ios::in //відкрити для читання
ios::nocreate //приводить до неуспіху, якщо файл не існує
ios::noreplace //приводить до неуспіху, якщо файл існує
ios::out //відкрити для виводу
ios::trunc //відсікти файл до нульової довжини
access - визначає, з якими атрибутами відкритий файл
0 нормальний файл (по замовчуванню)
1 - read-only
2 - hidden
4 - system
8 - archive
Якщо в силу будь-яких причин файл не може бути відкритий, значення потоку рівне 0.
Для закривання файла використовується функція-член close.
Для фіксування кінця файла використовується функція-член eof(), прототип якої
int eof();
Вона повертає ненульову величину, коли досягається кінець файла і навпаки.
Детальнішу інформацію про потоки вводу/виводу можна знайти в довідкових посібниках.
2.2. Класи
Класи є однією з важливих частин мови C++. Для того, щоб створити об’єкт, в мові C++ потрібно спочатку визначити його загальний вигляд, використовуючи ключове слово class. З синтаксичної точки зору клас подібний на структуру. Розглянемо в якості прикладу клас, який визначає тип під назвою stack. З його допомогою можна створити реальний стек.
Клас може містити відкриту і закриту частини. По замовчуванню, всі члени класу є закритими. Наприклад, змінні stck і tos є закритими. Це означає, що до них неможливо звернутися з функцій, які не є членами класу stack. Таким чином, досягається інкапсуляція – доступ до закритих елементів класу строго контролюється. В класі також можна визначити закриті функції, які можуть викликатись іншими членами класу.
Для того, щоб відкрити елементи класу, (тобто зробити їх доступними для інших частин програми), необхідно оголосити їх з допомогою ключового слова public. Всі змінні чи функції, розміщені в розділі public, доступні для довільних функцій програми. По суті, зовнішня частина програми отримує доступ до об’єкту саме через його відкриті функції-члени. Хоча змінні можна оголошувати відкритими, цього потрібно уникати. Навпаки, всі дані рекомендується оголошувати закритими, контролюючи доступ до них з допомогою відкритих функцій. Крім того, слід звернути увагу на те, що після ключового слова public у визначенні класу stack стоїть двокрапка.
Функції init(), push(int i) і pop() називаються функціями-членами, оскільки вони є частиною класу stack. Змінні stck і tos називаються змінними-членами (або даними-членами). Нагадаємо, що об’єкт створює зв’язок між кодом і даними. Тільки функції-члени мають доступ до закритих членів свого класу. Отже, доступ до змінних stck і tos мають тільки функції init(), push(int i) і pop().
Визначивши клас, можна створити об’єкт цього типу. По суті, ім’я класу стає новим специфікатором типу даних. Наприклад, наступний оператор створює об’єкт з іменем mystack типу stack.
stack mystack;
Оголошуючи об’єкт класу, ми створюємо екземпляр (instance) цього класу. В даному випадку змінна mystack є екземпляром класу stack. Крім того, об’єкти можна створювати, вказуючи їх ім”я зразу після визначення класу, тобто після закриваючої фігурної дужки (аналогічно, як екземпляр структури).
В мові C++ з допомогою ключового слова class визначається новий тип даних, який можна використовувати для створення об’єктів цього типу. Отже, об’єкт – це екземпляр класу. В цьому розумінні він нічим не відрізняється від інших змінних, наприклад, від змінної, яка являє собою екземпляр типу int. Іншими словами, клас є логічною абстракцією, а об’єкт – її реальним втіленням, яке існує в пам’яті комп’ютера.
Визначення простого класу має наступний вигляд:
class ім’я класу
{
закриті змінні і функції
public:
відкриті змінні і функції
} список імен об’єктів ;
Природно, що список імен об’єктів може бути пустим.
Всередині визначення класу stack функції-члени ідентифікуються з допомогою своїх прототипів. Нагадаємо, що в мові C++ всі функції повинні мати прототип. Таким чином, прототипи є невід’ємною частиною класу. Прототип функції-члена, розміщеної всередині визначення класу, має той же зміст, що і прототип звичайної функції.
Кодуючи функцію-член класу, необхідно повідомити комп’ютеру, якому саме класу вона належить. Для цього перед її іменем слід вказати ім’я відповідного класу.
Оператор “::” називається оператором дозволу області видимості (scope resolution operator). Він повідомляє компілятору, що дана версія функції push() належить класу stack, тобто функція push() перебуває в області видимості класу stack.
Завдяки оператору дозволу області видимості компілятор завжди знає, якому класу належить кожна з функцій.
Посилаючись на член класу зовні, завжди слід вказувати конкретний об’єкт, якому цей член належить. Для цього використовується ім’я об’єкта, за яким слідує оператор “.” і ім’я члена. Це правило стосується як до даних-членів, так і до функцій-членів. Ось як, наприклад, викликається функція init(), яка належить об'єкту stack1.
stack stack1, stack2;
stack1.init();
В цьому фрагменті створюються два об’єкти - stack1 і stack2, а потім об’єкт stack1 ініціалізується з допомогою функції init(). Зверніть увагу на те, що змінні stack1, stack2 представляють собою два різних об’єкти. Таким чином, ініціалізація об’єкту stack1 не означає ініціалізації об’єкту stack2. Об’єкти stack1, stack2 пов’язує лишень те, що вони є екземплярами одного і того ж класу.
Всередині класу функції-члени можуть викликати одна одну і звертатись до змінних-членів, не використовуючи оператор “.”. Цей оператор необхідний лише тоді, коли звертання до функцій і змінних-членів відбувається ззовні класу.
Не забувайте: закриті члени об’єкта доступні тільки функціям-членам, які належать цьому ж об’єкту. Наприклад, в попередньому прикладі оператор
stack1.tos = 0; /* Помилка, змінна tos є закритою */
не можна було б помістити в функцію main(), оскільки змінна tos є закритим членом об’єкта stack1.
Ввід і вивід для типу, визначеного користувачем (перевантаження операторів).
Розглянемо процедуру перевантаження операторів вводу-виводу (“>>” і “<<”) для обєктів, визначених користувачем. Оператор виводу “<<” називається оператором вставки (insertion operator), тому, що він вставляє символи в потік. Аналогічно, оператор вводу “>>” називають оператором видобування (extraction operator), тому що він вибирає символи з потоку. Функції, які перевантажують оператори вставки і видобування називають функціями вставки (insetrers) і видобувавння (extractors) відповідно.
Створимо клас two_d для роботи в декартовій площині. Загальна форма первантаженого оператора вводу (видобування) така:
istream & operator >> (istream any_stream, class_name & object)
{ return any_stream; } // програма вводу користувача
Перший параметр мусить бути посиланням до об’єкта типу istream. Другий параметр також посилання. Це необхідно, тому що змінні класу class_name може бути змінена. Функція повертає посилання на об’єкт типу istream.
Загальнийй вивід (вставка) для типу користувача будується подібним чином:
ostream & operator << (ostream & any_stream, class_name object)
{ return any_stream; } // програма виводу користувача
ЗАВДАННЯ ДО ЛАБОРАТОРНОЇ РОБОТИ(1 варіант)
1. Створити клас three_d для роботи з точками трьохмірного простору (змінні типу float). Написати програму, яка використовуючи перевантажений оператор вводу-виводу, демонструє ввід і вивід елементів даного класу (на прикладі 5-ти елементів типу three_d).
КОД ПРОГРАМИ
#include<iostream.h>
#include<conio.h>
#include<stdio.h>
class three_d{
private:
float a, b, c;
public:
void vvid_vuvid() {
cout<<"\t"<< a <<","<<b<<","<<c;
}
void vvid_vuvid(float A, float B, float C) {
a=A;
b=B;
c=C; }}
main (){
float x, y, z;
three_d t[5];
cout << " Will be entered the coordinates of 5 points \n";
for (int i=0;i<5;i++){
cout<<"Press coordinates " <<i+1<<" point \n";
cout<<"\n";
cin>>x >>y >>z;
t[i].vvid_vuvid(x,y,z); }
cout<<"RESULTAT";
cout<<"\n";
for(i=0;i<5;i++){
t[i].vvid_vuvid();
cout<<"\n";}
getch();}
РЕЗУЛЬТАТ ВИКОНАННЯ
ВИСНОВОК
На основі лабораторної роботи я ознайомився з особливостями обєктно-орієнтованої мови програмування С++.