Wykład 1
Klasy - wprowadzenie

Trochę historii...

Wśród wielu odpowiedzi na pytanie o cel nauki jedna niewątpliwie jest właściwa: jak najdokładniejsze opisanie otaczającego nas świata. Podobnie sprawa wygląda z językami programowania. Ich rozwój był konsekwencją dążenia do coraz precyzyjniejszego i zgodnego z intuicją opisu rzeczywistości. Nie będziemy się tutaj w historię języków zagłębiać ale pokażemy pewne idee, które doprowadziły do postania dzisiejszych języków.

Programowanie liniowe

Główne cechy:

Programowanie strukturalne

Główne cechy:

Programowanie zorientowane obiektowo

Główne cechy:

Kilka terminów...

Dziedziczenie - przykładzik

  1. pojazd: 
    własności (dane): prędkość, położenie
    działania: Stój, PoruszajSię
    
  2. pojazdCzterokołowy: taki sam jak typ pojazd oraz dodatkowo
    własności: ilośćDobrychKół
    działania: SkręćWLewo, SkręćWPrawo
    
  3. wodnosamolot: taki sam jak typ pojazd oraz dodatkowo
    własności: szybkośćTonięcia
    działania: Startuj, Ląduj
    
  4. pojazdKosmiczny:
    własności: zapasPowietrza
    
  5. pojzadMarsjański: taki sam jak typ pojazdCzterokołowy oraz
                      taki sam jak typ pojazdKosmiczny oraz
    własności: stanNaładowaniaAkumulatorów
    działania: RozłóżBaterieSłoneczne, ŁadujAkumulatory
    

Klasa - jak to napisać?

Definicja klasy


class nazwaKlasy
{
  //ciało klasy;
  //określa z czego składa się klasa
}
Listing 1.1

Składniki klasy


//Same pola:

class pojazd
{
public:
  coord polozenie;
  float predkosc;
};

//Pola + metody:

class pojazd
{
public:
  coord polozenie;
  float predkosc;
  int Stoj();
  int PoruszajSie();
};
Listing 1.2

Delkarowanie zmiennej typu zadeklarowanej klasy


pojazd mojSamochod;
pojazd rower;
pojazd szybowiecEli;
Listing 1.3
Powyżej mamy przykład trzech egzemplarzy obiektu typu pojazd. Każdy z nich ma swoje własne położenie i swoją własną prędkość. Jednak w pamięci występuje tylko po jednym egzemplarzu każdej z funkcji bez względu czy obiekt jest jeden czy więcej.

Odnoszenie do składników

Do zawartości klasy możemy odnieść się na trzy sposoby:

pojazd mojSamochod;
pojazd * wsk;
pojazd & superBolid = mojSamochod;

mojSamochod.predkosc = 60;
wsk =& mojSamochod;
wsk -> predkosc = 60;
superBolid.predkosc = 60;
Listing 1.4

Gdzie wpisać ciało funkcji?


class coord
{
public:
  float x;
  float y;
  float z;
  void SetX(float t) //ta funkcja jest inline
  {
    x=t;
  }
  void SetY(float t);
  void SetZ(float t);
  float GetX(void);
  float GetY(void);
  float GetZ(void);
};

...

//ta funkcja nie jest inline
float coord :: SetY(float t)
{
  y=t;
}

//ta funkcja jest inline
inline float coord :: SetZ(float t)
{
  z=t;
}

...
Listing 1.5

konstruktor i destruktor - po co?!

Przypatrzmy się poniższemu przykładowi

class coord
{
...
};

class pojzad
{
...
}

int main()
{
  pojazd mojSamochod;
  
  //nadanie wartości początkowych
  mojSamochod.predkosc = 60;
  mojSamochod.polozenie.SetX(127);
  mojSamochod.polozenie.SetY(50);
  mojSamochod.polozenie.SetZ(20);
  
  ...
}
Listing 1.6
Na pewną niedogodność natrafiamy w momencie nadawania wartości początkowych - wielokrotnie zmuszeni jesteśmy odwoływać się do pól i/lub metod klasy. O wiele wygodniej byłoby napisać

pojazd mojSamochod(60, 127, 50, 20);
Listing 1.7
Nie możemy nadać wartości początkowy bezpośrednio w klasie, gdyż wówczas wszystkie egzemplarze tej klasy miałyby takie same wartości początkowe a nie o to tutaj chodzi. Szczęśliwie problem ten pozwalają rozwiązać konstruktory. Zapis z listingu 1.7 będzie możliwy po wprowadzeniu poniższych zmian

class pojzad
{
public:
  coord polozenie;
  float predkosc;
  int Stoj();
  int PoruszajSie();
  pojazd(float v, float a1, float a2, float a3);
};

//konstruktor
pojazd :: pojazd(float v, float a1, float a2, float a3)
{
  predkosc = v;
  polozenie.SetX(a1);
  polozenie.SetY(a2);
  polozenie.SetZ(a3);
}
Listing 1.8
Skoro możemy coś skonstruować więc fajnie by było jeśli możnaby to zniszczyć :)) I tu pojawia się destruktor.

//destruktor
pojazd :: ~pojazd()
{
  printf("Uległem biodegradacji...\n");
}
Listing 1.9
Zapamiętajmy więc, że konstruktor i destruktor to specjalne funkcje składowe.

Pierwszy program


#include <stdio.h>

class first
{
public:
  int zmiennaTypuInt;
  void ChangeInt(int i);
  void Wypisz();
  first (int i);
  ~ first();
};

void first :: ChangeInt(int i)
{
  printf("Wywołanie metody ChangeInt() z argumentem o wartości %d;\n",i);
  printf("zmiana wartości z %d na %d\n",zmiennaTypuInt,i);
}

void first :: Wypisz()
{
  printf("Wywołanie funkcji Wypisz(); zmiennaTypInt=%d\n",zmiennaTypuInt);
}

first :: first(int i)
{
  printf("Wywołanie konstruktora z argumentem o wartosci %d\n",i);
  zmiennaTypuInt=i;
}

first :: ~first()
{
  printf("Wywołanie destruktora;\n");
  printf("zmienna %d kończy żywot\n", zmiennaTypiInt);
}

int main()
{
  first myClass(2);
  
  myClass.Wypisz();
  myClass.ChangeInt(7);
  myClass.Wypisz();
  return 0;
}
Listing 1.10