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:
- Wszystkie zmienne są globalne
- Brak wielokrotnego wykonywania tej samej części programu bez powtarzania jego kodu. Jedyną instrukcją przekazującą sterowanie programu innej jego części jest instrukcja skoku GOTO.
Programowanie strukturalne
Główne cechy:
- Podział programu na niezależne składowe (procedury), które mogą korzystać ze swoich własnych danych (zmienne lokalne) niedostępnych dla innych procedur. W ten sposób, mówiąc nieformalnie, każdy program składa się z wielu mniejszych programów.
- Pojawia się bardzo ważna idee - abstrakcja. Przyglądając się poszczególnym elementom programu (procedurom) skupiamy się na tym co dany element ma robić a nie w jaki sposób.
Programowanie zorientowane obiektowo
Główne cechy:
- Pozwala wiązać dane z działaniami i przedstawiać pod postacią jednego typu. Typ określa sposób zachowania pewnych danych jako całości. Mówimy "typ", gdyż kreować będziemy nie jeden konkretny obiekt, ale raczej klasę obiektów.
- Enkapsulacja, ukrywanie informacji.
- Pozwala definiować (naturalne) zależności między różnymi obiektami.
- Pozwala definiować nowe obiekty w oparciu o już istniejące. Dziedziczymy wcześniej napisane komponenty rozszerzając je o nowe własności.
Kilka terminów...
- klasa - wzorzec opisujący dane i dopuszczalne sposoby działania na tych danych.
- obiekt - zadeklarowana zmienna typu zdefiniowanej klasy.
- metoda - funkcja zdefiniowana w danej klasie.
- pole - zmienna zadeklarowana w danej klasie.
Dziedziczenie - przykładzik
-
pojazd:
własności (dane): prędkość, położenie
działania: Stój, PoruszajSię
-
pojazdCzterokołowy: taki sam jak typ pojazd oraz dodatkowo
własności: ilośćDobrychKół
działania: SkręćWLewo, SkręćWPrawo
-
wodnosamolot: taki sam jak typ pojazd oraz dodatkowo
własności: szybkośćTonięcia
działania: Startuj, Ląduj
-
pojazdKosmiczny:
własności: zapasPowietrza
-
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:
- obiekt.składnik
- wskaźnikNaObiekt -> składnik
- referencja.składnik
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.
- konstruktor - funkcja składowa wywoływana automatycznie ilekroć powołujemy do życia nowy obiekt danej klasy.
- destruktor - funkcja składowa wywoływana automatycznie gdy obiekt danej klasy ma być zlikwidowany.
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
|