Програмен език C++
Част 28
.
Статични променливи на класа
(Static Members)
.
(съдържание)
.
В тази лекция ще бъде разгледано свойство на променливите на класа, което е много близко по концепция до тази на запазване на променливите, описана в лекция 27.  Освен това, статичните променливи на класа илюстрират връзките между клас, обект, функциите на класа и променливите на класа.

1. Статични променливи на класа (Static Member Data). Досега използвахме само променливи, които имат различни стойности за всеки един обект от този клас. Но в много приложения е необходимо да има променливи, които са с една и съща стойност за всички обекти. Нека си представим, например, моделирането на състезателна игра с коли и един от класовете е състезателната кола. Скоростта, количеството гориво и степента на повреда са конкретни променливи на всеки един обект състезателна кола, но дължината на пистата или препятствията по нея (които са еднакви за всички коли) са променливи, които не само имат една и съща стойност, но и трябва да са достъпни за всички обекти от класа. Разбира се, можем да ги моделираме като външни променливи, но както споменахме този подход има своите затруднения и се избягва в ООП, още повече че има статични променливи на класа.

2. Създаване на статични променливи на класа (Creating Static Data). Синтактисът за създаване на такива данни е донякъде необичаен, защото първо в класа се пише декларация на променливата, а извън класа тя се дефинира. Например

class aclass
{
  private:
    static int stavar;   // declaration
  // other declarations & definition in the class
   };

int aclass::stavar = 77;   // definition

Декларацията използва ключовата дума static. Дефиницията използва името на класа и оператора за решение за обхвата (scope resolution operator), :: , въведен в лекция 24 (той там бе използван за функции на класа, дефинирани извън класа). В примера по-горе променливата stavar е инициализирана, но ако не беше тя щеше да получи по подразбиране стойност 0 (съответно 0.0 за реалните променливи). Веднъж дефинирана статичната променлива може да бъде достъпна само от функциите на класа, т.е. нейният обхват е класа.

3. Достъп до статични променливи на класа (Accessing Static Data). Както споменахме всяка една функция на класа има достъп до статичните променливи на същия клас, но е по-уместно да се създаде специална функция, която има достъп до дадена статична променлива (или няколко статични променливи). Т.е. опираме до т.н. статични функции на класа (static functions). Такава функция е задължително необходима ако искаме да предадем стойността на статичната променлива на променлива извън класа или на променлива на друг обект (вижте примера от т. 4).

Статичната функция на класа също се дефинира с ключовата дума static и изглежда като обичайна функция на класа, но тя се извиква не от конкретен обект на класа, а с името на класа, последвано от оператора за решение за обхвата (scope resolution operator), :: .  Ето един схематичен пример

class aclass
{
  private:
  // decalations & definitions

  public:
    static int stafunc()  // function definition
    {
      // can access only static member data
    }
};
main()
{
  // other statments
  aclass::stafunc();       // function call
  // other statments
}

Статичната функция на класа не може да се обръща към нестатичните променливи на класа - това е очевидно от това, че се извиква с името на класа (в горния пример aclass::stafunc();). Също така тези функции могат да се извикват преди да е създаден обект от класа.

4. Пример за броене на обектите (Count-the-Objects Example). Това е пример от книгата на Лафоор [1]. Програмата създава клас widget (джаджа). Всяка джаджа има сериен номер, стартиращ от 10,000. Статичната променлива total_widgets държи сметка колко обекта са създадени - тя се променя във функцията на класа init(). В тази функция първо става присвояване към серийния номер на стойност 10,000 плюс броя джаджи (т.е. първата има номер 10,000), а после се увеличава статичната променлива total_widgets: забележете че операторът ++ е постфиксен оператор (postfix operator).

// static.cpp
// demonstrates static data and functions

#include <iostream.h>
#include <conio.h>
using namespace std;

////////////////////////////////////////////////////////////////
class widget
{
   private:
      int widget_number;          // a widget's serial number
      static int total_widgets;   // all widgets made so far
                                  // NOTE: declaration only
   public:
      void init()                 // initialize one widget
      {
        widget_number = 10000 + total_widgets++;
      }

      int get_number()            // get a widget's number
      {
         return widget_number;
      }

      static int get_total()      // get total widgets
      {
         return total_widgets;
      }
};  // class widget

int widget::total_widgets = 0;    // NOTE: definition

void main()
{
   cout << "Total widgets = " << widget::get_total() << endl;
   widget w1, w2, w3;    // create widgets
   w1.init();            // initialize them
   w2.init();
   w3.init();

   cout << "w1 = " << w1.get_number() << endl;
   cout << "w2 = " << w2.get_number() << endl;
   cout << "w3 = " << w3.get_number() << endl;
   cout << "Total widgets = " << widget::get_total() << endl;

  // added to stop the screen
  getch();

}

Статичната функция се извиква не с конкретен обект, а с името на класа: widget::get_total(). Изпълнението на тази програма дава следното на екрана

Total widgets = 0
w1 = 10000
w2 = 10001
w3 = 10002
Total widgets = 3

Ако главната функция я изменим по този начин (т.е. да следим броя на джаджите след всяко извикване на init())

void main()
{
   cout << "Total widgets = " << widget::get_total() << endl;
   widget w1, w2, w3;    // create widgets
   w1.init();            // initialize them
   cout << "Total widgets = " << widget::get_total() << endl;
   w2.init();
   cout << "Total widgets = " << widget::get_total() << endl;
   w3.init();
   cout << "Total widgets = " << widget::get_total() << endl;

   cout << "w1 = " << w1.get_number() << endl;
   cout << "w2 = " << w2.get_number() << endl;
   cout << "w3 = " << w3.get_number() << endl;

  // added to stop the screen
  getch();

изходът на екрана ще е следният

Total widgets = 0
Total widgets = 1
Total widgets = 2
Total widgets = 3
w1 = 10000
w2 = 10001
w3 = 10002

Обърнете внимание, че и в двата варианта на главната функция статичната функция се извиква преди още да са създадени обекти от класа с твърдението

   widget w1, w2, w3;    // create widgets

В тази програма статичната променлива total_widgets е използвана във функцията init(), но както ще видим в следващите лекции това е по-добре да се направи в конструктура на класа.

.
(съдържание)
.
Литература
.
[1] Robert Lafore; C++ Interactive Course. Waite Group Press, Macmillan Computer Publishing, 1996.
.
Автор: Проф. Процесор Аритметиков
.
[ това е материал от брой 29 от април 2009 г на списание "Коснос" www.kosnos.com ]

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