Програмен език C++
(съдържание)

Част 2. Що е това обект?

В тази лекция ще се запознаем с основните черти на обектно-ориентираното програмиране (ООП) и по-специално с понятията клас и обект. Материалът ще бъде илюстриран с реален пример, разясняващ няколкото понятия, които се въвеждат тук  - променлива на обекта (instance data) и функция на класа (member function),

Разбира се, не всичко ще стане напълно ясно на нашия читател, но много от концепциите и понятията ще бъдат обяснени в следващите лекции и илюстрирани с кратки примери.

1. Обекти от действителността, които се моделират в една програма. Както споменахме в предишната лекция с програмни обекти се моделират реални обекти от действителността, от които се извличат най-съществените признаци и дейности. Признаците на реалните обекти се моделират с променливи, а дейностите - с функции. Без да претендираме за изчерпателност, нека дадем няколко групи от обекти, които са подходящи за моделиране с програмни обекти.

A. Социални и учрежденски структури

- работниците и служещите в едно предприятие;
- преподавателите, служителите и учениците в едно училище или университет;
- военнослужещите в едно поделение (полк, дивизия и т.н.).
B. Обекти от техниката
- самолетите в едно въздушно пространство;
- светофарите в един град;
- транспортната техника на едно предприятие;
- реакторите и апаратите в един химически завод.
C. Обекти в компютърни игри
- колите в една игра за състезания;
- бойците и жителите в една игра с битки;
- самолети, танкове, оръдия и други военни средства в една игра с битки;
- замъци, укрепления и други постройки в играта.
D. Сбирки от данни
- инвентарът на едно предприятие;
- личните досиета на служителите в едно предприятие;
- речник от думи;
- сбирка от спектри (ИЧ спектри, мас-спектри, ЯМР спектри и т.н.);
- списък от химични съединения, представени с тяхната структура, име и различни физикохимични данни.
E. Структури от данни, дефинирани от потребителите
- ъгли;
- вектори, матрици и тензори;
- дати;
- комплексни числа;
- точки в равнината или пространството;
F. Природни структури при компютърни симулации
- животните в един ареал;
- дърветата в един ареал;
- микробите в една бактериологична колония;
- невроните в една мозъчна структура;
- клетките в една клетъчна структура.
G. Конструкции от данни (Data-storage constructs)
- специализирани масиви (customized arrays);
- стекове (stacks);
- свързани списъци (linked lists) ;
- двоични дървета (binary trees);
- графи (linear graphs).
2. Състояние и фукционалност на обекта. Всеки един от изброените по-горе обекти се описва с някакви характеристики, които формират състоянието на обекта, и извършва определен вид дейности, които определят неговата функционалност. Например едно комплексно число представлява набор от две реални числа - неговата реална и имагинерна стойности, z = a + bi. Същото число може да се описва още с модула си (абсолютната стойност) и неговата фаза - z = |z|exp(iq). Т.е. променливи в програмния обект "комплексно число" ще бъдат реалната и имагинерната част, но програмистът може да добави още две променливи - модула и фазата. Комплексните числа се събират и изваждат и се умножават и делят едно на друго, т.е. в обекта е необходимо да има функции, които извършват тези дейности. Всъщност, това е възможно само с обектно-ориентираното програмиране и се състои в дефинирането на нови оператори +, -, * и /, които извършват действията с обектите.

!В текста частите от програмния код са дадени със шрифт 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.

Автор: Проф. Процесор Аритметиков

.
[ това е материал от брой 11 от септември 2007 г. на списание "Коснос" www.kosnos.com ]

Keywords: С++,  OOP programming , C++ , Classes , Inheritance , Reusability , Creating New Data Types , Polymorphism and Overloading
Ключови думи: клас , обект, обектно ориентирано програмиране , полиморфизъм