Міністерство освіти і науки України
Національний університет „Львівська політехніка”
Кафедра ЕОМ
/
Звіт
про виконання лабораторної роботи №4
з дисципліни:
“Програмування, частина 2 (Об’єктно-орієнтоване програмування)”
на тему:“ Класи та об’єкти ”
2017
Мета: познайомитися із класами та об’єктами.
Теоретичні відомості
Визначення класу
Основна відмінність будь-якої об’єктно-орієнтованої мови програмування від інших не об’єктно-орієнтованих мов програмування є можливість створення нових визначених користувачем типів, що називаються класами. Клас – це визначений користувачем тип з даними-елементами (властивостями) та функціями-елементами (методами), що являються членами класу. Він зазвичай описує певну абстракцію якоїсь сутності реального світу з її властивостями і можливими діями. Змінна типу клас називається об’єктом. Об’єкт – це вже не абстракція, а елемент реального світу, який може володіти певними характеристиками, які задаються властивостями в класі, та діяти згідно операцій заданих методами у класі. Оголошення класу в мові С++ має наступний синтаксис (не обов’язково щоб клас мав всі секції чи спадкував базовий клас):
class ім'я_класу : список_базових_класів {
publіc:
// Оголошення загальнодоступних (відкритих) членів класу, що можуть бути доступні звідусіль
protected:
// Оголошення захищених членів класу, що доступні тільки для похідних класів
prіvate:
// Оголошення закритих членів класу, що доступні лише членам цього класу, та не можуть бути змінені чи викликані з-за меж класу напряму, а лише за посередництвом методів з інших секцій
};
Члени класу (властивості і методи), оголошені після ключового слова publіc стають відкритими членами. Це означає, що вони доступні:
усім іншим членам класу;
дружнім конструкціям (класам, методам, функціям);
членам похідних класів;
з-під об’єктів класу після створення об’єктів; після створення об’єкту класу до його членів можна звертатися лише якщо вони є загальнодоступними.
Члени класу, оголошені після ключового слова prіvate, стають закритими членами. Вони доступні:
для інших членів того ж класу;
друзям класу.
Якщо в класі не оголошено секцій, але визначено методи чи властивості, то вони вважатимуться такими, що оголошені у секції prіvate. Для модифікації властивостей, що оголошені в секції private створюються спеціальні методи, які здійснюють цю модифікацію. Назви таких методів прийнято починати зі слова set. На жаргоні такі методи інколи називають сетерами. Для читання властивостей, що оголошені в секції private створюються спеціальні методи, які безпечно повертають значення цих властивостей. Назви таких методів прийнято починати зі слова get. На жаргоні такі методи інколи називають ґетерами.
Члени класу, оголошені після ключового слова protected, стають захищеними членами. Вони доступні:
для інших членів того ж класу;
членам похідних класів;
друзям класу.
Таблиця 4.1. Рівні доступу членів класу
Доступ
private
protected
public
Інші члени цього класу
+
+
+
Друзі класу
+
+
+
Члени похідних класів
-
+
+
З-під об’єктів класу
-
-
+
Оголошення класу містить оголошення даних-елементів (властивостей) та функцій-елементів (методів) класу. Одна з фундаментальних основ ООП передбачає інкапсуляцію даних, тобто дані мають бути недоступними ззовні, а лише за посередництвом загальнодоступних методів класу. Оголошення методів має вигляд оголошення прототипу функції в середині однієї з секцій класу, зазвичай у секції public. Якщо методи є службовими і не мають бути доступні ззовні, тоді їх розміщують в секції private або protected. Сама ж реалізація методу може знаходитись як усередині класу (тоді оголошення методу в класі має вигляд оголошення функції з тілом), так і поза оголошенням класу (тоді у класі оголошується прототип функції, а її тіло визначається за межами класу). Але один з найфундаментальніших принципів розробки програмного забезпечення мовою С++ полягає у розмежуванні інтерфейсу класу від його реалізації. Тому при побудові програми мовою C++ кожне оголошення класу зазвичай розміщують у заголовочний файл *.h назва якого співпадає з назвою класу, а реалізацію методів цього класу – у файл *.cpp із тим ж іменем, що й *.h файл. Заголовочні файли включаються (за допомогою директиви #іnclude) у кожен файл, у якому використовується клас, а файли з вихідними кодами компілюються і компонуються з файлом, що містить головну програму (main-функцію).
При визначенні методу класу за межами класу необхідно зв'язати ім'я відповідного методу з ім'ям класу. Зв'язок встановлюється шляхом написання імені класу, оператора розширення області видимості (::) та імені методу. Оскільки різні класи можуть мати елементи з однаковими іменами, то оператор розширення області видимості дозволяє однозначно ідентифікувати методи конкретного класу.
тип ім’яКласу :: ім’яМетоду (списокПараметрів)
{
// тіло методу
}
Областю видимості властивостей та методів класу є клас, тобто все що оголошене в середині класу є видиме і доступне за іменем елементів в середині класу без додаткових маніпуляцій.
Статичні властивості і методи
Статичні дані-елементи (властивості) оголошуються в класі, а ініціалізуються за межами класу (не у конструкторах). На відміну від інших властивостей вони належать класу, а не об’єкту. Тобто вони єдині для всіх об’єктів певного класу і зміни одним об’єктом вплинуть на всі об’єкти даного класу. Якщо статичні властивості оголошені в секції public, то вони будуть завжди доступні незалежно від того чи створено хоч один об’єкт класу. За допомогою статичних властивостей зручно реалізовувати лічильники, наприклад, лічильники створених об’єктів класу.
Синтаксис оголошення і ініціалізації статичних властивостей:
// оголошення статичної властивості
class ім'я_класу {
prіvate:
static тип назваВластивості;
};
// ініціалізація статичної властивості
тип ім'я_класу :: назваВластивості = значення;
Приклад оголошення і ініціалізації статичних властивостей:
// оголошення статичної властивості
class CMyClass
{
prіvate:
static int m_counter;
};
// ініціалізація статичної властивості
int CMyClass :: m_counter = 0;
Статичні методи оголошуються з використанням ключового слова static при оголошенні методу. На відміну від нестатичних методів дані методи існують завжди, навіть якщо нема жодного екземпляру класу. Тому їх можна викликати з будь якого місця програми не створюючи при цьому об’єкту класу. Для виклику статичного методу слід вказати назву класу, оператор розширення області видимості (::), назву статичного методу, передати йому параметри і поставити крапку з комою в кінці виклику. Статичні методи не мають доступу до членів класу, тому вони мають реалізуватися самодостатніми, тобто такими, що не потребують для своєї роботи інших даних, ніж ті що вони містять в собі і ті, що передаються їм через параметри. Одним з прикладів використання статичних методів є методи, що обчислюють різні тригонометричні функції.
Методи доступу до об’єкта
Змінна класу (об’єкт, екземпляр класу) оголошується у відповідності з наступним синтаксисом:
Ім’яКласу ім’яЗмінної(списокПараметрів);
При оголошенні змінної відбувається створення відповідного об'єкта. При цьому виконується виклик одного з конструкторів класу цього об'єкта. Для доступу до елементів об'єкта використовується оператор крапка (.).
Доступ до об'єкта можна одержати через вказівник на цей об'єкт. При цьому до членів об'єкта звертаються не за допомогою оператора крапка, а за допомогою оператора "стрілка" (->).
Синтаксис динамічного створення об’єкту класу має наступний вигляд:
ім’яКлассу * ім’яЗмінної = new ім’яКласу(параметри);
У даному випадку з вільної пам'яті кучі виділяється ділянка пам'яті, достатня для збереження об'єкта зазначеного класу. Для створеного об'єкта автоматично викликається конструктор відповідно до заданих параметрів. Як результат, оператор new повертає адресу створеного об'єкта, яка зберігається у вказівнику. Після цього можна здійснювати доступ до динамічно створеного об'єкта за допомогою цього вказівника.
Після того, як динамічно створений об'єкт стає непотрібним, його необхідно знищити за допомогою оператора delete. Знищення об'єкта приводить до виклику деструктора, звільненню пам'яті, відведеної під даний об'єкт і поверненню цієї пам'яті у вільну пам'ять кучі.
Кожен об’єкт у мові C++ містить спеціальний вказівник thіs, який містить адресу об’єкту якому він належить. Крім цього цей вказівник неявно автоматично передається будь-якому нестатичному методові класу при його виклику, вказуючи цим самим на об'єкт з-під якого метод був викликаний. Як і будь-який вказівник у 32-ох бітній системі він займає 4 байти в пам’яті.
Ще одним способом доступу до об'єкта є доступ через посилання. Посилання по суті є псевдонімом (нікнеймом) назви об’єкту класу. Його зручно використовувати при передачі об’єкту або змінної методам або функціям. При цьому копіювання даної змінної чи об’єкту не відбувається, а функція чи метод отримує сам об’єкт напряму, який просто відомий для неї під іншою назвою. Оскільки посилання є лише іншою назвою об’єкту або змінної, то в пам’яті комп’ютера воно не займає ніякого місця, що дозволяє її економити та пришвидшувати обробку даних при викликах функцій і методів. Небезпекою використання посилань є те, що функція чи метод працює з об’єктом на пряму, а не з його копією, в результаті чого є небезпека ненароком змінити стан об’єкта (значення даних-елементів об’єкту). Єдина ситуація, коли не можна використовувати посилання, а слід використовувати вказівники – це передача масивів через параметри. Синтаксис оголошення посилання має наступний вигляд:
ім’яКлассу & ім’яЗмінної;
Приклад використання посилання:
CMyClass myclass;
CMyClass & refObj = myclass;
CMyClass *pmyclass = new CMyClass();
refObj = *pmyclass;
// функція void func(CMyClass & rObj);
void func(refObj);
void func(myclass);
У даному прикладі створюється об’єкт myclass класу CMyClass. Створений об’єкт присвоюється посиланню refObj. Тепер myclass і refObj – це один і той самий об’єкт відомий за різними назвами. Потім динамічно створюється об’єкт класу CMyClass адреса якого присвоюється вказівнику pmyclass. Після чого даний вказівник розіменовується і об’єкт на який він вказує присвоюється посиланню refObj. Потім здійснюються 2 виклики функції func, яка оголошена як func(CMyClass & rObj); і приймає посилання на об’єкт класу CMyClass. Хоча в першому випадку у функцію передається посилання на об’єкт класу, а у другому – об’єкт класу вона в обох випадках працюватиме з переданим об’єктом як з посиланням rObj. Перевагою такого способу передачі параметрів є економія пам’яті, відсутність необхідності автоматичного створення копії об’єкту чи змінної при передачі її через параметр, звертання до членів об’єкту відбувається як до членів об’єкту класу, а не за вказівником, оригінал переданого об’єкту змінюється в процесі обробки, завдяки чому немає потреби повертати оброблену копію об’єкту з функції. Недоліками даного способу є неможливість передавати масиви через посилання і те, що не завжди об’єкт має змінюватися і ризик помилково його змінити може мати велику ціну. Також бувають ситуації, коли слід працювати з копією об’єкту в методі, тоді в метод слід передавати об’єкт за значенням, а не за посиланням чи вказівником.
Завдання:
Написати програму яка буде використовувати класи та продемонструвати функціонування розроблених методів цих класів.
У моїй програмі створено два класи WorkerTable і WorkerDataProcessor.
В файлі WorkerDataProcessor.h класу WorkerDataProcessor оголошено методи за допомогою яких ми формуватимемо масиви рядків та масиви об’єктів.
В файлі WorkerDataProcessor.cpp класу WorkerDataProcessor прописана реалізація цих методів.
В файлі WorkerTable.h класу WorkerTable олошено методи які повертають властивості об’єктів.
В файлі WorkerTable.cpp класу WorkerTable прописана реалізація цих методів.
В файлі Sourse.cpp в якому є виконавчий метод main створюємо об’єкт який буде викликати наші методи.
Код WorkerDataProcessor.h
#pragma once
#include"WorkerTable.h"
class WorkerDataProcessor
{
public:
string *getStrArray(int numerator);
WorkerTable** getArray(string* lineArray, int numerator);
int getNumberLine();
};
Код WorkerDataProcessor.cpp
#include "WorkerDataProcessor.h"
string * WorkerDataProcessor::getStrArray(int numerator) //Прописуємо метод класу що створює масив строк з рядків файлу та повертає вказівник
{
string *lineArray = new string[numerator];
ifstream infile;
infile.open("Dovidnuk2.txt");
if (!infile)
{
cout << "Неможливо вiдкрити файл" << endl;
}
for (int i = 0; i < numerator; i++)
{
getline(infile, lineArray[i]);
}
return lineArray;
}
WorkerTable ** WorkerDataProcessor::getArray(string * lineArray, int numerator) //Прописуємо метод класу що створює масив обєктів класу та повертає вказівник
{
WorkerTable ** infoArray = new WorkerTable*[numerator];
for (int i = 0; i < numerator; i++)
{
//Парсинг строки
vector<std::string> localArray;
size_t pos = 0, found;
while ((found = lineArray[i].find_first_of(';', pos)) != string::npos) {
localArray.push_back(lineArray[i].substr(pos, found - pos));
pos = found + 1;
}
localArray.push_back(lineArray[i].substr(pos));
infoArray[i] = new WorkerTable(localArray[0], localArray[1], localArray[2], atoi(localArray[3].c_str()), atoi(localArray[4].c_str()), localArray[5]);
}
return infoArray;
}
int WorkerDataProcessor::getNumberLine() //Прописуємо метод що підраховує кількість рядків
{
int numerator = 0;
char *str = new char[1024];
ifstream infile;
infile.open("Dovidnuk2.txt");
// Перевірка чи файл відкривається
if (!infile)
{
cout << "Неможливо вiдкрити файл" << endl;
}
// Підраховуємо кількість рядків
while (!infile.eof())
{
infile.getline(str, 1024, '\n');
numerator++;
}
numerator--;
return numerator;
}
Код WorkerTable.h:
#pragma once
#include <string>
#include <iostream>
#include<fstream>
#include<iomanip>
#include <vector>
using namespace std;
class WorkerTable
{
private:
string typeOfWork;
string workerName;
string workerSurname;
int yearsNumber;
int experience;
string birthday;
public:
WorkerTable(string typeOfWork, string workerName, string workerSurname, int yearsNumber, int experience, string birthday) {
this->typeOfWork = typeOfWork;
this->workerName = workerName;
this->workerSurname = workerSurname;
this->yearsNumber = yearsNumber;
this->experience = experience;
this->birthday = birthday;
}
//Створюємо методи для встановлення і отримання властивостей класу
string getTypeOfWork();
string getWorkerName();
string getWorkerSurname();
int getYearsNumber();
int getExperience();
string getBirthday();
};
Код WorkerTable.cpp:
#include "WorkerTable.h"
//Прописуєм методи для встановлення і отримання властивостей класу
string WorkerTable::getTypeOfWork() {
return this-> typeOfWork;
}
string WorkerTable::getWorkerName() {
return this-> workerName;
}
string WorkerTable::getWorkerSurname() {
return this-> workerSurname;
}
int WorkerTable::getYearsNumber() {
return this -> yearsNumber;
}
int WorkerTable::getExperience() {
return this-> experience;
}
string WorkerTable::getBirthday() {
return this-> birthday;
}
Код Sourse.cpp:
#include "WorkerDataProcessor.h"
int main()
{
setlocale(LC_CTYPE, "ukr");
WorkerDataProcessor data; //Створюємо обєкт класу
int numerator = data.getNumberLine(); //Обєкт викликає метод що підраховує кількість рядків
string* stringArray = data.getStrArray(numerator); //Обєкт викликає метод що створює масив строк з рядків файлу
WorkerTable** pointerStringArray = data.getArray(stringArray, numerator); //Обєкт викликає метод задопомогою якого ми отримуємо масив з обєктів нашого файлу
cout << setw(20) << "Тип роботи" << setw(20) << "Iм'я" << setw(17) << "Прiзвище" << setw(25) << "Кiлькiсть рокiв" << setw(11) << "Стаж" << setw(21) << "Дата народження" << setw(20) << endl;
for (int i = 0; i < numerator; i++) {
cout.width(20);
cout << pointerStringArray[i]->getTypeOfWork();
cout.width(20);
cout << pointerStringArray[i]->getWorkerName();
cout.width(20);
cout << pointerStringArray[i]->getWorkerSurname();
cout.width(17);
cout << pointerStringArray[i]->getYearsNumber();
cout.width(15);
cout << pointerStringArray[i]->getExperience();
cout.width(20);
cout << pointerStringArray[i]->getBirthday();
cout.width(20);
cout << endl;
}
}
Результат виконання програми:
/
Рис.1 - Ескіз екрана виконаної програми(Вивід інформації про робітників на екран)
Висновок: виконуючи четверту лабораторну роботу я отримав знання та навички у створенні класів та використанні методів що в них прописані. Ці навички стануть мені в пригоді при роботі над курсовою роботою. В подальшому я планую навчитися виконувати редагування цього списку робітників.