Програмен език C++
Част 21

Структури
(Structures)

(съдържание)

В C++ структурите са потребителски специфицирани типове, които съдържат сбирка от наименовани компоненти (наречени членове), като тази сбирка (collection) се определя от потребителя. В част 15 видяхме, че масивите са програмни структури, които обединяват данни от един и същи тип. За разлика от тях структурите в C и C++ обединяват в едно цяло данни от различен тип и това е нужно, когато тези данни логически обособяват някаква сборна характеристика. В C++, обектите заместват структурите в C, но въпреки това има ситуации, в които те са полезни: структури се използват когато групираме няколко променливи, но те не се използват толкова интензивно в програмата, че да бъдат специфицирани като клас.

1. Спецификация на структура (Specifying a Structure). Тя започва в началото с ключовата дума struct като след нея следва името на типа, наричан още етикет (tag). След името следва тялото на спецификацията, заградено с големи скоби и накрая точка и запетая. Тялото на спецификацията може да се състои от списък от декларации на различни променливи. Тези отделни променливи се наричат членове на структурата (members), за разлика от елементите на масива (elements). Спецификацията не създава променлива от тип структура, а само показва как ще изглежда този тип данни.

Следващият код показва спецификацията на една структура, в която се пазят името на служителя, дължината на това име и служебният номер на служителя.

struct employee
{
  char name[20];
  int n;
  unsigned long serial_number;
};

Както виждате декларацията на структурата прилича много на декларацията на един клас (сравнете с декларацията на клас със същото име в част 16), но въпреки това структурите и класовете се използват за съвсем различни цели: в класовете имаме функции, които оперират с неговите данни, докато обикновено в структурите нямаме такива функции. C++ в сравнение със C разширява функционалността на структурите и те могат да имат функции в тях, но по-принцип това се избягва в програмистката пратика: за това ще поговорим в края на тази лекция.

2. Дефиниране на структурни променливи (Defining Structure Variables). Дефинирането на такива променливи е като с всеки един тип в C++ - първо се изписва името на типа и след него се изписват имената на променливите, разделени със запетайка. Следният код дефинира две променливи от типа employee.

employee e1, e2;      // deffinition of two structure varibles

Спецификацията и декларацията може да се обединят в едно по следния начин, като се съкрати кодът:

struct employee
{
  char name[20];
  int n;
  unsigned long serial_number;
} e1, e2;

Даже може да се премахне етикетът (името) на структурата employee и дефинирането на тези две променливи да изглежда по следния начин:

struct
{
  char name[20];
  int n;
  unsigned long serial_number;
} e1, e2;

Обикновено това съкращаване се прави в малки програми, докато в големите проекти то може да доведе до неясноти.

Също така още при дефиницията една структурна променлива може да се инициализира (Initializing Structure Variables) както е дадено по-долу:

{
  char name[20];
  int n;
  unsigned long serial_number;
} e1 = {"Plamen", 7, 1234567890}, e2;

3. Достъп до членовете на структурата (Accessing Structure Members). Той става с помощта на точковия оператор за достъп (dot operator), например e1.n = 0; или cout << e2.serial_number;. В ляво от точката стои името на променливата от тип структура, а в дясно - името на члена на структурата. По-долу е даден примерен код как могат да се променят членовете на променливата e1 от дефиницията по-горе. Сравните този код с кода от  част 16 за да видите колко е по-елегантно да се работи с функции на класа (защото същата купчина програмни редове ще трябва да бъдат написани и за втора променлива от този тип!).

  char ch;

  e1.n = 0;
  cout << "   Enter name: ";
  do
  {
    ch = getche();       // get one char at a time
    e1.name[e1.n] = ch;        // store in “name” array
    ++e1.n;
  } while (ch != '\r');  // quit if “Enter” key

  cout << "\n   Enter serial number: ";
  cin >> e1.serial_number;

4. Примерна програма със структури. Ето и една програма от курса на Лафоор [1], която е модификация на една по-ранна версия на програма за симулиране на стек stack1.cpp от част 16.

// strustak.cpp
// class models a stack, uses struct for array and index

#include <iostream.h>
#include <conio.h>      // for getche()

struct stackette               // structure
{
   int arr[20];                // storage array
   int top;                    // index of top of stack
};

class Stack                    // class
{
   private:
      stackette st;            // structure variable

   public:
      void init()              // initialize index
      {
         st.top = -1;
      }

      void push(int var)       // place an item on the stack
      {
         st.arr[++st.top] = var;
      }

      int pop()                // remove an item from the stack
      {
         return st.arr[st.top--];
      }
};  // class Stack

void main()
{
   Stack s1;                   // create a stack object

   s1.init();                  // initialize it
   s1.push(11);                // push 3 items onto stack
   s1.push(12);
   s1.push(13);

   cout << s1.pop() << endl;  // pop 3 items and display them
   cout << s1.pop() << endl;
   cout << s1.pop() << endl;

   // stop the flow on the monitor
   getch();

}  //end main

Тъй като двете променливи arr и top като едно цяло определят стека те се обединяват в една структура stackette. Съответно функции на класа също са променени, защото двете стари променливи са вече членове на една нова.

Обръщането към членовете на тази структура става с точковия оператор за достъп, например st.top = -1; или return st.arr[st.top--];. Обърнете внимание, че главната функция в двете програми stack1.cpp и strustak.cpp е една и съща, въпреки че класът бе променен, и това е защото интерфейсът на класа е запазен..

5. Структури и класове. Има повече прилики между тези два типа, отколкото споменахме досега. В структурата може да има функции, както и функциите на класа може да бъдат премахнати. Структурата може да има и конструктор и деструктор. Ето една примерна програма, която ви демонстрира този факт.

// emp.cpp
// models an employee with a structure
// structure has constructor and destructor

#include <iostream.h>
#include <conio.h>                  // for getche()

struct emp
{
  char name[20];
  int n;
  unsigned long serial_number;

  emp()      // constructor
  {
    cout << "I am the constructor" << endl;
  }
  ~emp()     // destructor
  {
    cout << "I am the destructor" << endl;
  }

};

void main()
{
   emp e1;

   char ch;

   e1.n = 0;
   cout << "   Enter name: ";
   do
   {
     ch = getche();             // get one char at a time
     e1.name[e1.n] = ch;        // store in “name” array
     ++e1.n;
   } while (ch != '\r');        // quit if “Enter” key

   cout << "\n   Enter serial number: ";
   cin >> e1.serial_number;

   cout << "Employee data" << endl;

   cout << "   Name = ";

   for (int j = 0; j < e1.n; ++j)   // display one character
      cout << e1.name[j];           // at a time

   cout << "\n   Serial number = " << e1.serial_number << endl;

}  //end main

По-долу е даден изходът на екрана при примерно изпълнение на тази програма:

I am the constructor
   Enter name: Plamen
   Enter serial number: 31374143
Employee data
   Name = Plamen
   Serial number = 31374143
I am the destructor

Въпреки тези възможности, в програмистката практика класовете и обектите се използват с техните функции, конструктори и деструктори, докато структурите се използват без функции в тях. Също така структурите са удобни за съхраняване на данни във файлове.

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

.
(съдържание)
.
Литература
.
[1] Robert Lafore; C++ Interactive Course. Waite Group Press, Macmillan Computer Publishing, 1996.

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

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

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