Informatyka dla klas II

Klasy

Klasa (ang. class) jest obiektem, z którym, oprócz danych, jak w strukturze, skojarzono funkcje operujące na tych danych. Funkcje klasy nazywamy funkcjami składowymi (ang. member functions). Stanowią one integralną część definicji klasy.

Powodem wprowadzenia klas było w pewnym sensie uproszczenie programowania. Wyobraźmy sobie telewizor. Chcę oglądać jakiś program - czy muszę koniecznie znać w najdrobniejszych szczegółach jego budowę? Oczywiście nie, wystarczy znać funkcje klawiszy sterujących, a to co w środku, to dla inżynierów. Podobnie jest z klasami. Klasa udostępnia programowi tzw. interfejs, poprzez który program może się komunikować z klasą. Cechy implementacyjne mogą być ukrywane. W tym celu definicja klasy zawiera tzw. część publiczną - dostępną dla programu, oraz część prywatną - na użytek samej klasy, do której zewnętrzne funkcje nie posiadają dostępu.

Oprócz pól danych klasa może zawierać funkcje składowe, będące jej integralną częścią. Funkcje te mogą być publiczne - wtedy program może z nich korzystać, lub prywatne - na potrzeby wewnętrzne klasy.

Klasa może zawierać specjalne funkcje zwane konstruktorami i destruktorami. Funkcja konstruktor ma taką samą nazwę jak nazwa klasy. Jej zadaniem jest odpowiednie zainicjowanie pól danych w czasie tworzenia klasy - w przypadku struktury inicjowaniem pól musiał się zajmować program. Konstruktorów może być kilka, ale muszą się różnić parametrami. Destruktor jest funkcją o nazwie klasy poprzedzoną tyldą ~. Zadaniem destruktora jest posprzątanie po klasie, gdy będzie ona usuwana z pamięci. Jest to istotne, jeśli klasa sama zawiera dynamiczne struktury - wtedy destruktor zwalnia wcześniej przydzieloną na nie pamięć. Konstruktor i destruktor jest wywoływany automatycznie, programista nic nie musi specjalnie robić w tym celu. Jeśli w klasie nie zdefiniujemy swojego konstruktora lub destruktora, to zostanie utworzony standardowy konstruktor i destruktor.

Definicja klasy wygląda następująco:

 

class nazwa_klasy
{
   public:                // deklaracja pól i funkcji publicznych
       pole_danych;       // pola dostępne dla programu
       pole_danych;
       ...
       nazwa_klasy();     // konstruktor
       ~nazwa_klasy()     // destruktor

       funkcja_składowa;  // funkcje dostępne dla programu
       funkcja_składowa;
       ...
   private:               // deklaracja pól i funkcji prywatnych
       pole_danych;       // pola dostępne tylko dla funkcji składowych klasy
       pole_danych;
       ...
       funkcja_składowa;  // funkcje dostępne tylko wewnątrz klasy
       funkcja_składowa;
};

 

Jeśli funkcje klasy są krótkie, to można je zdefiniować bezpośrednio w definicji klasy. W przypadku dłuższych funkcji definiujemy je na zewnątrz w sposób następujący:

Konstruktor - funkcja nic nie zwraca, brak w niej polecenia return:

 

nazwa_klasy::nazwa_klasy(ewentualne_parametry)
{
   treść konstruktora
}

 

Destruktor - funkcja nic nie zwraca, brak w niej polecenia return:

 

nazwa_klasy::~nazwa_klasy()
{
   treść destruktora
}

 

Funkcja składowa:

 

typ_wyniku nazwa_klasy::funkcja_składowa(ewentualne_parametry)
{
   treść funkcji składowej;
   return wynik;
}

 

Funkcje składowe posiadają bezpośredni dostęp do danych klasy - jawnie nie musimy do nich przekazywać parametru będącego klasą. Niejawnie taki parametr jest zawsze przekazywany - wewnątrz każdej funkcji składowej nazywa się on this, lecz nie ma go na liście parametrów

Przykładowa klasa realizująca funkcje stosu

 Poniżej mamy nasz program ze stosem przerobiony na klasę. Sam stos jest tablicą dynamiczną, której rozmiar przekazujemy w trakcie tworzenia zmiennej - parametr ten trafia do konstruktora klasy.

 

// Klasa - stos
// (C)2016 I LO w Tarnowie
//------------------------

#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

// Tutaj definiujemy klasę

class stack
{
    public:               // interfejs klasy dla programu

      stack(int n);       // konstruktor stosu n-elementowego
      ~stack();           // destruktor
      void push(int x);   // funkcja składowa
      int  top();         // funkcja składowa
      void pop();  

    private:              // elementy prywatne do użytku wewnętrznego

      int sptr, * S, limit;
};

// Definicja konstruktora

stack::stack(int n)
{
    limit = n;            // zapamiętujemy rozmiar stosu
    S = new int[n];       // tworzymy tablicę dynamiczną
    sptr = 0;             // zerujemy wskaźnik stosu
    cout << "KONSTRUKTOR - STOS UTWORZONY" << endl;
}

// Definicja destruktora

stack::~stack()
{
    delete [] S;          // usuwamy tablicę dynamiczną
    cout << "DESTRUKTOR - STOS USUNIETY" << endl;
}

// Funkcja zapisuje na stos

void stack::push(int x)
{
    if(sptr < limit) S[sptr++] = x;
    else cout << "STOS PELNY!!!" << endl;
}

// Funkcja odczytuje szczyt stosu

int stack::top()
{
    if(sptr) return S[sptr - 1];
    cout << "STOS PUSTY!!!" << endl;
    return -1;
}

// Funkcja usuwa daną ze szczytu stosu

void stack::pop()
{
  if(sptr) sptr--;
  cout << "DANE USUNIETE" << endl;
}

// Program główny

int main()
{
  stack stos(5);      // zmienna klasy, stos o rozmiarze 5
  int i,x;

  srand(time(NULL));  // inicjujemy generator pseudolosowy

  cout << "ZAPIS 7 LICZB NA STOS\n";

  for(i = 1; i <= 7; i++)
  {
     x = rand();
     cout << x << endl;
     stos.push(x);
  }

  cout << "\nODCZYT 7 LICZB ZE STOSU\n";

  for(i = 1; i <= 7; i++)
  {
     x = stos.top();
     cout << x << endl;
     stos.pop();
  }

  return 0;
}

 

Klasy dynamiczne

Klasy również mogą być tworzone dynamicznie. Procedura jest następująca:

 

nazwa_klasy * wskaźnik; // zmienna typu wskaźnik do klasy

 

W pamięci rezerwujemy odpowiedni blok pamięci i adres tego bloku umieszczamy we wskaźniku:

 

wskaźnik = new nazwa_klasy;

 

Dostęp do pól danych uzyskujemy za pomocą operatora ->.

 

wskaźnik -> nazwa_pola

 

Dostęp do funkcji składowych również uzyskujemy za pomocą operatora ->:

 

wskaźnik -> funkcja_składowa(parametry);

 

Gdy klasa dynamiczna przestanie być potrzebna, usuwamy ją z pamięci:

 

delete wskaźnik;

 

Poniżej nasz program z klasą dynamiczną:

 

// Klasa dynamiczna - stos
// (C)2016 I LO w Tarnowie
//------------------------

#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

// Tutaj definiujemy klasę

class stack
{
    public:               // interfejs klasy dla programu

      stack(int n);       // konstruktor stosu n-elementowego
      ~stack();           // destruktor
      void push(int x);   // funkcja składowa
      int  top();         // funkcja składowa
      void pop();  

    private:              // elementy prywatne do użytku wewnętrznego

      int sptr, * S, limit;
};

// Definicja konstruktora

stack::stack(int n)
{
    limit = n;            // zapamiętujemy rozmiar stosu
    S = new int[n];       // tworzymy tablicę dynamiczną
    sptr = 0;             // zerujemy wskaźnik stosu
    cout << "KONSTRUKTOR - STOS UTWORZONY\n";
}

// Definicja destruktora

stack::~stack()
{
    delete [] S;          // usuwamy tablicę dynamiczną
    cout << "DESTRUKTOR - STOS USUNIETY\n";
}

// Funkcja zapisuje na stos

void stack::push(int x)
{
    if(sptr < limit) S[sptr++] = x;
    else cout << "STOS PELNY!!!" << endl;
}

// Funkcja odczytuje szczyt stosu

int stack::top()
{
    if(sptr) return S[sptr - 1];
    cout << "STOS PUSTY!!!" << endl;
    return -1;
}

// Funkcja usuwa daną ze szczytu stosu

void stack::pop()
{
  if(sptr) sptr--;
  cout << "DANE USUNIETE" << endl;
}

// Program główny

int main()
{
  stack * stos;         // wskaźnik do klasy
  int i,x;

  stos = new stack(5);  // tworzymy klasę dynamicznie

  srand(time(NULL));    // inicjujemy generator pseudolosowy

  cout << "ZAPIS 7 LICZB NA STOS\n";

  for(i = 1; i <= 7; i++)
  {
     x = rand();
     cout << x << endl;
     stos -> push(x); // wywołanie funkcji składowej
  }

  cout << "\nODCZYT 7 LICZB ZE STOSU\n";

  for(i = 1; i <= 7; i++)
  {
     x = stos -> top(); // wywołanie funkcji składowej
     cout << x << endl;
     stos -> pop();
  }

  delete stos;         // usunięcie klasy dynamicznej z pamięci

  return 0;
}

 

Ćwiczenie

Utwórz klasę listy kierunkowej z operacjami push_front, pop_front, push_back, print, remove.


   I Liceum Ogólnokształcące   
im. Kazimierza Brodzińskiego
w Tarnowie

©2024 mgr Jerzy Wałaszek

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji
GNU Free Documentation License.

Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl

W artykułach serwisu są używane cookies. Jeśli nie chcesz ich otrzymywać,
zablokuj je w swojej przeglądarce.
Informacje dodatkowe