Част 2. Що е това обект?
В тази лекция ще се запознаем с основните черти на обектно-ориентираното програмиране (ООП) и по-специално с понятията клас и обект. Материалът ще бъде илюстриран с реален пример, разясняващ няколкото понятия, които се въвеждат тук - променлива на обекта (instance data) и функция на класа (member function),
Разбира се, не всичко ще стане напълно ясно на нашия читател, но много от концепциите и понятията ще бъдат обяснени в следващите лекции и илюстрирани с кратки примери.
1. Обекти от действителността, които се моделират в една програма. Както споменахме в предишната лекция с програмни обекти се моделират реални обекти от действителността, от които се извличат най-съществените признаци и дейности. Признаците на реалните обекти се моделират с променливи, а дейностите - с функции. Без да претендираме за изчерпателност, нека дадем няколко групи от обекти, които са подходящи за моделиране с програмни обекти.
A. Социални и учрежденски структури
- работниците и служещите в едно предприятие;B. Обекти от техниката
- преподавателите, служителите и учениците в едно училище или университет;
- военнослужещите в едно поделение (полк, дивизия и т.н.).
- самолетите в едно въздушно пространство;C. Обекти в компютърни игри
- светофарите в един град;
- транспортната техника на едно предприятие;
- реакторите и апаратите в един химически завод.
- колите в една игра за състезания;D. Сбирки от данни
- бойците и жителите в една игра с битки;
- самолети, танкове, оръдия и други военни средства в една игра с битки;
- замъци, укрепления и други постройки в играта.
- инвентарът на едно предприятие;E. Структури от данни, дефинирани от потребителите
- личните досиета на служителите в едно предприятие;
- речник от думи;
- сбирка от спектри (ИЧ спектри, мас-спектри, ЯМР спектри и т.н.);
- списък от химични съединения, представени с тяхната структура, име и различни физикохимични данни.
- ъгли;F. Природни структури при компютърни симулации
- вектори, матрици и тензори;
- дати;
- комплексни числа;
- точки в равнината или пространството;
- животните в един ареал;G. Конструкции от данни (Data-storage constructs)
- дърветата в един ареал;
- микробите в една бактериологична колония;
- невроните в една мозъчна структура;
- клетките в една клетъчна структура.
- специализирани масиви (customized arrays);2. Състояние и фукционалност на обекта. Всеки един от изброените по-горе обекти се описва с някакви характеристики, които формират състоянието на обекта, и извършва определен вид дейности, които определят неговата функционалност. Например едно комплексно число представлява набор от две реални числа - неговата реална и имагинерна стойности, z = a + bi. Същото число може да се описва още с модула си (абсолютната стойност) и неговата фаза - z = |z|exp(iq). Т.е. променливи в програмния обект "комплексно число" ще бъдат реалната и имагинерната част, но програмистът може да добави още две променливи - модула и фазата. Комплексните числа се събират и изваждат и се умножават и делят едно на друго, т.е. в обекта е необходимо да има функции, които извършват тези дейности. Всъщност, това е възможно само с обектно-ориентираното програмиране и се състои в дефинирането на нови оператори +, -, * и /, които извършват действията с обектите.
- стекове (stacks);
- свързани списъци (linked lists) ;
- двоични дървета (binary trees);
- графи (linear graphs).
!В
текста частите от програмния код са дадени със шрифт Courier
New и син
цвят.
!!Под
спецификация
на класа, ще разбираме дефиницията на класа, докато обявяването на обекти
(променливи) от този клас ще наричаме
декларация.
3. Класове. В ООП обектите са конкретна реализация (an instance or an instantiation ) на класовете. Класът е вид (тип) данни, а обектите са негова конкретна реализация, подобно на променливата a от декларацията int a , която променлива е реализация (т.е. конкретен представител, за който се отделя памет в програмата) на типа int; за разлика от класовете в C++ типът int е предефиниран тип, т.е. не е необходимо да се дефинира от програмиста.
Ето няколко декларации в една C++ програма, при които се използват предварително дефинираните типове в езика:
int
day;
char
letter;
int
count;
float
pi;
Един клас се специфицира с ключовата дума class и тялото на спецификацията, заградено с големи скоби и завършващо с точка и запетая (с // се отбелязват коментари в програмата - от тях до края на реда написаното се пропуска от компилатора). Ето една спецификация на класа Complex_num.
class
Complex_num // <-- ключовата дума “class” and името
на класа Complex_number
{
// <-- отваряща голяма скоба
// <-- от тук надолу се пишат другите програмни редове
private
float a; // <-- реалната
част на комплексното число
float b; // <-- имагинерната
част на комплексното число
float modulus; // <-- модула на комплексното число
float phase; // <-- фазата на комплексното число
public
float Calc_Abs() // <-- първата функция на класа; скобите
след името означават функция
{
}
Complex_num Add(Complex_num z1, Complex_num z2) // <-- втората
функция на класа и т.н.
{
}
// <-- до тук се пишат другите програмни редове
};
// <-- затваряща голяма скоба, следвана от точка и запетая
Ако искаме да създадем обект от този клас, просто пишем декларацията, подобно на декларирането на променливи от другите типове данни:
Complex_num
Znum; // <-- името на класа Complex_num следвано от
името на променливата Znum
// и завършващо с точка и запетая
Програмата, чак след декларацията на обекта Znum, отделя необходимата памет за него, докато спецификацията на класа не води до това.
Както видяхме с помощта на обектите могат да се дефинират нови типове данни. Също така могат да се определят и нови операции с тези нови типове данни, а също и ново значение на операторите +, -, ++, --, * и /.
Веднъж специфицирани класовете могат да се наследяват и променят като се добавят нови функционалности към тях, което изключително много улеснява програмистите и спомага за повторното използване на вече изготвените и тествани класове.
Програма за управление на полетите
За да илюстрираме казаното по-горе ще разгледаме спецификациите на един клас и дефинициите в програма за управление на полетите, която се дава в книжката за самообучение към комплекта C++ Builder, Standard, Version 4.0 на Борланд [1]. Програмата главно е разположена в три файла - главно, защото компилаторът използва и проектни файлове с разширение .bpr и някои други помощни файлове. Трите файла са airplane.h, airplane.cpp и airport.cpp. Първият файл се нарича заглавен файл (на жаргон се казва хедър файл) и съдържа спецификацията на класа Airplane. Дефиницията се дава с тези редове:
class
Airplane
{
public:
Airplane(const char* _name, int _type = AIRLINER);
~Airplane();
virtual int GetStatus(char* statusString);
int GetStatus()
{
return status;
}
int Speed()
{
return speed;
}
int Heading()
{
return heading;
}
int Altitude()
{
return altitude;
}
void ReportStatus();
bool SendMessage(int msg, char* response,
int spd = -1, int dir = -1, int alt = -1);
char* name;
protected:
virtual void TakeOff(int dir);
virtual void Land();
private:
int speed;
int altitude;
int heading;
int status;
int type;
int ceiling;
};
Дефиницията започва с ключовата дума class и името на класа - Airplane. Цялата дефиниция се загражда с големи скоби { }, като след затварящата скоба се поставя точка и запетая, };. В дефиницията на класа има три ключови думи - public, protected и private. Последната ключова дума, означава "частни" и ограничава достъпа чрез обектите до данните (или функциите), които са дефинирани след нея. Тези полета (данни и/или функции) са достъпни само в класа. Първата ключова дума ("публични"), обратно, позволява тези функции и/или данни да са достъпни чрез обектите. Именно функциите в тази част позволяват да се осъществи достъп до данните в защитената част. Втората ключова дума означава "защитени" и нейната функция е нещо средно между другите две: по-късно в този курс ще се запознаем с нея.
Както може да се очаква, данни на класа "Самолет" са скорост (speed), височина на полета (altitude), посока на полета (heading), състояние (status), тип на самолета (type) и таван на полета (ceiling). Тези данни се изразяват като целочислени променливи - това са шестте дефиниции след private.
Първите две функции в класа са така наречените конструктор и деструктор. Засега само ще споменем накратко тяхната роля, а в следващите лекции те ще бъдат разгледани подробно.
Airplane(const char* _name, int _type = AIRLINER);
~Airplane();
Конструторът има същото име като класа, Airplane, и след него има списък на параметри, затворени в кръгли скоби. Конструктурът се използва за първоначална инициализация на обектите от този клас - т.е. даване на стойност на променливите на обектите, както и някои други операции, като създавене на динамични променливи в хийпа (the heap). В случая се дава име на самолета (в динамичната променлива name) и се въвежда видът на самолета: ако видът не се въведе се подразбира, че самолета е лайнер (AIRLINER) - това се вижда от следното присвояване в дефиницията на конструктура по-горе:
int _type = AIRLINER.
Деструкторът започва с тилда, ~, и има същото име като класа; между тилдата и името Airplane няма разстояние. Деструкторът се грижи за освобождаване на заетата динамична памет от съответния обект - но за това по-подробно в следващите лекции: засега си мислете, че деструкторът изпълнява "последното желание" на един обект, който трябва да се премахне от паметта на компютъра.
В програмата дефинициите на на конструктура и деструктура са във файла airplane.h, а във файла airplane.cpp, са дадени техните декларации.
//
Constructor performs initialization
Airplane::Airplane(const
char* _name, int _type) :
type(_type), status(ONRAMP), speed(0), altitude(0), heading(0)
{
switch (type)
{
case AIRLINER : ceiling = 35000; break;
case COMMUTER : ceiling = 20000; break;
case PRIVATE : ceiling = 8000;
}
name = new char[50];
strcpy(name, _name);
}
//
Destructor performs cleanup.
Airplane::~Airplane()
{
delete[] name;
}
Следващите четири функции в класа GetStatus(), Speed(), Heading() и Altitude() връщат съответно статуса, скоростта, посоката и височината на самолета. Във файла airport.cpp първата се използва във вида GetStatus(buff);. Интересно е, че трите функции Speed(), Heading() и Altitude() не са използвани никъде в програмата! Може да сложите знак за начало на коментар, /*, преди първата и за край, */, след последната и програмата пак ще се компилира. Но имайте предвид, че при едно евентуално разширение на програмата, тези функции могат да влезнат в употреба.
В програмата чрез декларация на променливата planes се създава масив в динамичната памет (heap) от три показателя (pointers) към обекти от типа Airplane и след това те се инициализират.
// Set
up an array of Airplanes and create three Airplane objects.
Airplane
*planes[3];
planes[0]
= new Airplane("TWA 1040");
planes[1]
= new Airplane("United Express 749", COMMUTER);
planes[2]
= new Airplane("Cessna 3238T", PRIVATE);
Забележете, че номерацията на елементите на масива започва от нула, planes[0] - нещо което е много специфично за повечето програмни езици. Първият самолет е от тип AIRLINER, вторият - COMMUTER (това означава ежедневен превозвач), а третият - PRIVATE.
Със сигурност, засега материалът Ви звучи като на китайски, но това бе необходимият уводен текст, за да се хвърли поглед върху двете основни понятия в ООП - клас и обект. В следващата лекция ще започнем разглеждането на основните типове данни в езика (Basic C++ Data Types).
Формалните дефиниции на новите понятия (на английски и български) в тази и предишната лекция може да намерите в този материал.
Забележка [1]: C++ Builder is a trademark of Borland.
Автор: Проф. Процесор Аритметиков
Keywords: С++,
OOP programming , C++ , Classes , Inheritance , Reusability , Creating
New Data Types , Polymorphism and Overloading
Ключови думи: клас
, обект, обектно ориентирано програмиране , полиморфизъм