Міністерство освіти і науки України
Національний університет "Львівська політехніка"
Кафедра СКС
Звіт
З лабораторної роботи №5
з дисципліни: "Програмування ч. 2 (Об'єктно-орієнтоване програмування)"
на тему: "Класи та об'єкти"
Познайомитися із класами та об'єктами.
Короткі теоретичні відомості
Визначення класу
У мові C++ основна увага приділяється створенню нових визначених користувачем типів, що називаються класами. Клас – це визначений користувачем тип з даними-елементами та функціями-елементами (методами), що являються членами класу. Змінна типу клас називається об’єктом. Оголошення класу в мові С++ може мати наступний формальний опис:
class ім'я_класу : список_базових_класів {
publіc:
// Оголошення загальнодоступних членів класу
protected:
// Оголошення членів класу, доступних
// тільки для похідних класів
prіvate:
// Оголошення захищених членів класу
};
Члени класу, оголошені після ключового слова publіc стають відкритими членами. Це означає, що вони доступні як для інших членів класу і його друзів, так і для користувачів класу. Члени класу, оголошені після ключового слова prіvate, стають закритими членами. Вони доступні тільки для інших членів того ж класу і друзів класу. Члени класу, оголошені після ключового слова protected, стають захищеними членами. Вони доступні тільки для інших членів того ж класу, членів класів, похідних від даного, і друзів класу.
Оголошення класу містить оголошення даних-елементів та функцій-елементів класу. Оголошення функцій-елементів є прототипами функцій. Сама ж реалізація функції-елементів може знаходитись як усередині класу, так і поза визначенням класу. Але один з найбільш фундаментальних принципів розробки програмного забезпечення полягає у розмежуванні інтерфейсу класу від його реалізації. Тому при побудові програми на C++ кожне оголошення класу зазвичай розміщують у файл *.h , а реалізацію функцій-елементів цього класу – у файл *.cpp із тими ж іменами. Заголовочні файли включаються (за допомогою #іnclude) у кожен файл, у якому використовується клас, а файли з вихідними кодами компілюються і компонуються з файлом, що містить головну програму.
При визначенні методу класу необхідно зв'язати ім'я відповідного методу з ім'ям класу. Зв'язок встановлюється шляхом написанням перед ім'ям методу імені класу та оператора розширення області видимості (::). Оскільки різні класи можуть мати елементи з однаковими іменами, то оператор розширення області видимості дозволяє однозначно ідентифікувати функції-елементи конкретного класу.
тип ім’яКласу :: ім’яМетоду (списокПараметрів)
{
//тіло метода
}
Дані-елементи та функції-елементи класу мають областю дії клас. При області дії клас елементи класу безпосередньо доступні усім функціям-елементам цього класу і на них можна посилатися просто по імені.
Конструктори та деструктор
Після створення об'єкта його елементи можуть бути ініціалізовані за допомогою функції конструктора. Конструктор – це функція-елемент класу із тим же ім'ям, що і клас. Конструктор автоматично викликається при створенні об'єкта конкретного класу.
У класі може бути визначено кілька конструкторів, що відрізняються списком параметрів. При створенні об'єкта викликатися буде тільки один з них. Який саме – визначається зі способу створення об'єкта. Конструктор без параметрів або конструктор, у якого всі аргументи – це аргументи за замовчуванням, має спеціальну назву – конструктор за замовчуванням. Конструктор, що як свій єдиний параметр приймає посилання на постійний об'єкт цього ж класу, зветься конструктором копіювання. Він призначений для створення копії існуючого об'єкта і викликається при ініціалізації в операторі оголошення об'єкта або при передачі об'єкта класу за значенням у функцію (метод).
Деструктор – це спеціальна функція-елемент класу. Ім'я деструктора збігається з ім'ям класу, але перед ним ставиться символ тильда (~). Деструктор класу викликається при знищенні об'єкта – наприклад, коли виконувана програма залишає область дії, у якій був створений об'єкт цього класу. Насправді деструктор сам не знищує об'єкт – він виконує підготовку завершення перед тим, як система звільняє область пам'яті, у якій зберігався об'єкт, щоб використовувати її для розміщення нових об'єктів.
Деструктор не приймає жодних параметрів і не повертає жодних значень. Клас може мати тільки один деструктор – перевантаження деструктора не дозволяється.
Конструктори глобальних об'єктів викликаються перед тим як будь-яка функція даного файлу (включаючи maіn) почне виконуватися. Відповідні деструктори викликаються, коли завершується maіn або коли викликається функція exіt.
Конструктори автоматичних локальних об'єктів викликаються, коли процес виконання досягає місця, де об'єкти з'являються. Відповідні деструктори викликаються, коли покидається область дії об'єктів (тобто покидається блок, у якому ці об'єкти оголошені). Конструктори і деструктори для автоматичних об'єктів викликаються щораз при вході і виході з області дії.
Конструктори статичних локальних об'єктів викликаються відразу ж, як тільки процес виконання досягає місця, де об'єкти були вперше оголошені. Відповідні деструктори викликаються, коли завершується maіn або коли викликається функція exіt.
Методи доступу до об’єкта
Змінна класу (екземпляр класу) оголошується у відповідності з наступним синтаксисом:
Ім’яКласу ім’яЗмінної(списокПараметрів);
При оголошенні змінної відбувається створення відповідного об'єкта. При цьому виконується виклик одного з конструкторів класу цього об'єкта. Для доступу до елементів об'єкта використовується операція крапка (.).
Доступ до об'єкта можна одержати через вказівник на цей об'єкт. При цьому до членів об'єкта звертаються за допомогою оператора "стрілка" (->).
ім’яКлассу * ім’яЗмінної = new ім’яКлассу (списокПараметрів);
У даному випадку з вільної пам'яті виділяється ділянка пам'яті, достатня для збереження об'єкта зазначеного класу. Для створеного об'єкта автоматично викликається конструктор із заданими значеннями параметрів. Як результат, оператор new повертає адресу створеного об'єкта, яка зберігається у вказівнику. Згодом, доступ до динамічно створеного об'єкта здійснюється через цей вказівник.
Після того, як динамічно створений об'єкт стає непотрібним, його необхідно знищити. Знищення об'єкта приводить до виклику деструктора, звільненню пам'яті, відведеної під даний об'єкт і поверненню цієї пам'яті у вільну пам'ять. Знищення динамічно створеного об'єкта здійснюється оператором delete.
C++ містить спеціальний покажчик thіs. Це вказівник, що неявно автоматично передається будь-якому методові класу при його виклику і вказує на об'єкт, для якого метод був викликаний.
Ще одним способом доступу до об'єкта є доступ через посилання. Посилання є прихованим покажчиком і у всіх випадках його можна використовувати просто як ще одне ім'я об’єкта.
ім’яКлассу & ім’яЗмінної;
Приклад класу наведено нижче.
// Rectangle.h: interface for the Rectangle class.
//
class Rectangle
{
private:
double length;
double width;
public:
//конструктор по замовчуванню
Rectangle(double l = 1, double w = 1);
// конструктор копіювання
Rectangle(const Rectangle & rect);
// деструктор
virtual ~Rectangle();
double GetLength();
double GetWidth();
void PutLength(double);
void PutWidth(double);
double Area();
double Perimeter();
};
// Rectangle.cpp: implementation of the Rectangle class.
//
#include "Rectangle.h"
Rectangle::Rectangle(double l, double w )
{
length = l;
width = w;
}
Rectangle::Rectangle(const Rectangle & rect)
{
*this = rect;
}
Rectangle::~Rectangle()
{
}
double Rectangle::GetLength()
{
return length;
}
double Rectangle::GetWidth()
{
return width;
}
void Rectangle::PutLength(double l)
{
length = l;
}
void Rectangle::PutWidth(double w)
{
width = w;
}
double Rectangle::Area()
{
return length * width;
}
double Rectangle::Perimeter()
{
return 2.0 * (length + width);
}
// main.cpp
//
#include<iostream.h>
#include"Rectangle.h"
int main()
{
Rectangle rec1;
cout << "rec1" << endl;
cout << "length = " << rec1.GetLength() << endl;
cout << "width = " << rec1.GetWidth() << endl;
cout << "area = " << rec1.Area() << endl;
Rectangle rec2(10,10);
cout << "rec2" << endl;
cout << "length = " << rec2.GetLength() << endl;
cout << "width = " << rec2.GetWidth() << endl;
cout << "area = " << rec2.Area() << endl;
Rectangle rec5(rec2);
cout << "rec5" << endl;
cout << "length = " << rec5.GetLength() << endl;
cout << "width = " << rec5.GetWidth() << endl;
cout << "area = " << rec5.Area() << endl;
Rectangle rec6;
rec6 = Rectangle(6,3);
cout << "rec6" << endl;
cout << "length = " << rec6.GetLength() << endl;
cout << "width = " << rec6.GetWidth() << endl;
cout << "area = " << rec6.Area() << endl;
Rectangle* rec7;
rec7 = new Rectangle(2,3);
cout << "rec6" << endl;
cout << "length = " << rec7->GetLength() << endl;
cout << "width = " << rec7->GetWidth() << endl;
cout << "perimeter = " << rec7->Perimeter() << endl;
delete rec7;
Rectangle & rec8 = rec1;
cout << "rec8" << endl;
cout << "length = " << rec8.GetLength() << endl;
cout << "width = " << rec8.GetWidth() << endl;
cout << "perimeter = " << rec8.Perimeter() << endl;
return 0;
}
Результати виконання:
rec1
length = 1
width = 1
area = 1
rec2
length = 10
width = 10
area = 100
rec5
length = 10
width = 10
area = 100
rec6
length = 6
width = 3
area = 18
rec6
length = 2
width = 3
perimeter = 10
rec8
length = 1
width = 1
perimeter = 4
Завдання
Створити оголошення класу згідно варіанту та розробити програму-драйвер, яка продемонструє роботу класу.
Клас Quadrangle (чотирикутник). Клас зберігає Декартові координати чотирьох кутів чотирикутника. Конструктор приймає чотири групи координат. Повинні бути передбачені функції-елементи, що обчислюють периметр і площу, а також функція, що перевіряє чи передані координати визначають прямокутник. Довжиною повинне вважатися більше із двох вимірів.
Повний лістінг виконаної програми
Перевірено на дієздатність у Microsoft Visual C++ 2008 Express Edition
// Кафедра СКС
// ООП, Лабораторна робота № 3
// Виконав студент групи КІ-15
// Дунай Андрій
// 12 (3) варіант
#include <iostream>
#include <conio.h>
#include <math.h>
using namespace std;
int sqr(int n)
{
return n*n;
}
class Point
{
public:
Point(int nx = 0, int ny = 0);
int x, y;
};
Point::Point(int nx, int ny)
{
x=nx;
y=ny;
}
class Quadrangle
{
public:
Quadrangle();
Quadrangle(Point *p);
virtual ~Quadrangle();
float getPerimeter();
float getSquare();
float getLength(int part);
private:
Point coords[4];
};
Quadrangle::Quadrangle()
{
int i;
for(i=0;i<4;i++) coords[i]=Point(0,0);
}
Quadrangle::Quadrangle(Point *p)
{
int i;
for(i=0;i<4;i++) coords[i]=p[i];
}
Quadrangle::~Quadrangle()
{
int i;
for(i=0;i<4;i++) coords[i]=Point(0,0);
}
float Quadrangle::getLength(int part)
{
if(part<4) return sqrt((float)(sqr(coords[part].x-coords[(part+1)%4].x)+sqr(coords[part].y-coords[(part+1)%4].y)));
else return sqrt((float)(sqr(coords[2].x-coords[0].x)+sqr(coords[2].y-coords[0].y)));
}
float Quadrangle::getPerimeter()
{
int i;
float perimeter = 0;
for(i=0;i<4;i++) { perimeter+=getLength(i); }
return perimeter;
}
float Quadrangle::getSquare()
{
int i;
float p1, p2, a, b, c, d, e;
float s;
a=getLength(0);
b=getLength(1);
c=getLength(2);
d=getLength(3);
e=getLength(4);
p1=(a+b+e)/2;
p2=(c+d+e)/2;
s=sqrt(p1*(p1-a)*(p1-b)*(p1-e))+sqrt(p2*(p2-c)*(p2-d)*(p2-e));
return s;
}
int main(int argc, char* argv[])
{
Point coords[4];
int i;
for(i=0;i<4;i++)
{
cout << "Please enter quadrangle coodrinates (X" << i << " Y" << i << "): ";
cin >> coords[i].x;
cin >> coords[i].y;
}
Quadrangle q1(coords);
cout << "The perimeter is " << q1.getPerimeter() << "\n";
cout << "The square is " << q1.getSquare() << "\n";
_getch();
return 0;
}
Висновок
Я навчився працювати із структурами та екземплярами класів, ініціалізувати та знищувати їх, а також працювати з їх складовими частинами.
Підпис викладача