Typy programowania
• Strukturalne - wykorzystanie procedur i
dopasowanie do nich sposobu reprezentacji
danych
• Obiektowe - to dane potrzebne do opisania
obiektu i operacje opisujące interakcje
użytkownika z obiektem
Typ jest przypisaniem rzeczy i zjawisk do określonych kategorii.
• np. typ wartości całkowitych int pozwala na wykonywanie
obliczeń arytmetycznych
Typ zawiera informacje o:
- rozmiarze zajmowanym w pamięci
- rodzaju przechowywanej informacji
- możliwych do wykonania operacjach
Pojęcie typu
Pojęcie klasy
Nowy typ jest tworzony poprzez zadeklarowanie klasy:
class Pies
{
public:
unsigned int jegoWiek;
//zmienna
unsigned int jegoWaga;
//zmienna
void szczekaj();
//metoda czyli funkcja
};
Deklaracja nie rezerwuje pamięci, ale informuje o rozmiarze
każdego nowego Psa.
Pojęcie obiektu
Obiekt nowego typu jest tworzony tak jak zmienna:
Pies Gere;
//obiekt
Gere.jegoWiek = 8;
Gere.szczekaj();
Przypisanie jest skuteczne, jeśli zmienna lub wywoływana metoda są
typu public.
Przypisanie jest nieskuteczne, jeśli zmienna lub wywoływana
metoda są typu private (brak deklaracji typu public stanowi
wskazanie typu private).
Implementacja metod
void Pies::szczekaj();
{
std::cout << ”Hau hau\n”;
}
int Pies::pobierzWiek();
{
return jegoWiek;
}
int Pies::pobierzWage();
{
return jegoWaga;
}
Przykładowy program zasadniczy
#include <iostream>
//using (
namespace std
) std::cout;
/użyjemy samo polecenie -
cout
int main()
{
Pies Gere;
//obiekt
Gere.jegoWiek = 8;
Gere.jegoWaga = 48;
std::cout << ”Gere jest psem, który w wieku ” ;
std::cout << Gere.pobierzWiek() << ”lat, waży ” ;
std::cout << Gere.pobierzWage() << ”kg.\n” ;
Gere.szczekaj();
return 0;
};
Konstruktory
Konstruktor jest specjalną metodą klasy. Ma taka samą nazwę jak
klasa.
Nie można podać typu wyniku konstruktora. Nie można przekazać z
niego wyniku instrukcją return.
Można w nim wywoływać funkcje składowe klasy. Można go
wywołać jedynie przy tworzeniu nowego obiektu danej klasy. W klasie
można (i zwykle tak sie robi) zdefiniować wiele konstruktorów.
Konstruktor może mieć (nie musi) parametry. Konstruktor jest
odpowiedzialny za dwie rzeczy:
- zapewnienie, że obiekt będzie miał przydzieloną pamięć (to jest
sprawa kompilatora),
- inicjację obiektu (to nasze zadanie, realizuje je treść konstruktora).
Rodzaje konstruktorów
1/ Konstruktor bezargumentowy:
- można go wywołać bez argumentów,
- jest konieczny, jeśli chcemy mieć tablice obiektów tej klasy.
2/ Konstruktor domyślny:
- jeśli nie zdefiniujemy żadnego konstruktora, to kompilator sam
wygeneruje konstruktor domyślny (bezargumentowy),
- ten konstruktor nie inicjuje składowych typów prostych,
- dla składowych będących klasami lub strukturami wywołuje ich
konstruktory bezargumentowe,
- jeśli składowa będąca klasą lub strukturą nie ma konstruktora
bezargumentowego
bądź jest on niedostępny, generowanie
konstruktora domyślnego kończy sie błędem kompilacji.
Rodzaje konstruktorów cd..
3/ Konstruktor kopiujący:
- można go wywołać z jednym argumentem tej samej klasy,
przekazywanym przez referencje,
- jeśli żadnego takiego konstruktora nie zdefiniujemy, to kompilator
wygeneruje go automatycznie.
Uwaga: automatycznie wygenerowany konstruktor kopiujący kopiuje
obiekt składową po składowej, wiec zwykle się nie nadaje dla
obiektów zawierających wskaźniki(!)
- jest wywoływany niejawnie przy przekazywaniu parametrów do
funkcji i przy przekazywaniu wyników funkcji(!)
Konstruktory cd..
Przykładowy konstruktor:
Pies::Pies(int Wiek);
//konstruktor klasy Pies
{ jegoWiek = Wiek;
}
Pies::Pies();
//konstruktor domyślny
{ jegoWiek = 0;
}
Pies::Pies(int &Pies Gere);
//konstruktor kopiujący
{ jegoWiek = Gere; }
Konstruktor (jak i destruktor) należy zadeklarować typu public.
Tworzenie obiektów
Użycie konstruktora:
Pies Gere(5);
Pies Gere = Pies(5);
Pies *Czuka = new Pies(3);
Pies &Gere_ref = Gere;
//utworzenie referencji do obiektu
Pies Gere;
Referencja
Referencja jest alternatywną nazwą zmiennej lub obiektu:
int rats;
int &rodents = rats;
//rodents to referencja, obie zmienne mają tę
//samą wartość i adres
int *prats = &rats;
//prats to wskaźnik
*prats = 5;
// (=rats) jest to dereferencja
Referencja podobna jest wskaźnikowi, ale używana jest jako
parametr formalny funkcji, co powoduje, iż funkcja działa na
danych oryginalnych, a nie na kopii. Pozwala to na
modyfikowanie wartości więcej niż jednej zmiennej.
int refcube(int &ra)
{ ra *= ra * ra;
return ra; }
Destruktor
Gdy obiekt kończy swoje istnienie automatycznie zwalnia się
zajmowana przez niego pamięć. Nie dotyczy to jednak zasobów, które
obiekt sam sobie przydzielił w czasie swego istnienia.
Ten cel realizuje destruktor, będący metodą klasy. Klasa może mieć co
najwyżej jeden destruktor. Destruktor nie ma parametrów. Nie można
specyfikować typu wyniku destruktora. Nie można w nim używać
instrukcji return z parametrem.
Nazwa destruktora jest taka sama jak nazwa klasy, tyle że poprzedzona
tyldą:
Pies::~ Pies();
{
// jeśli nie ma żadnych zasobów do zwolnienia
}
Destruktor cd..
Destruktor jest odpowiedzialny za dwa problemy:
- zwolnienie pamięci zajmowanej przez obiekt (to sprawa
kompilatora),
- zwolnienie zasobów (to nasze zadanie, zwalnianie zasobów
zapisujemy jako treść destruktora).
Destruktor wywołuje sam kompilator. Jeśli nie utworzy go
programista w definicji klasy, to kompilator zrobi to niejawnie.
Wskaźniki
Przykłady użycia wskaźników:
int *ptr;
int* ptr;
int* p1, p2;
//p2 nie jest wskaźnikiem, więc czym?
double * ptr;
char * ptr;
long * fellow = 223344;
//niepoprawne, brak przypisan.
int * ptr = (int*) 0xB800000;
//poprawne
Przeciążanie operatorów
Ten sam symbol ma kilka znaczeń i kompilator wybiera jedno z nich
na podstawie kontekstu:
dotyczy to np.: <<, *, &,
/ (dzielenie różnych typów liczb),
- (odejmowanie, negacja );
Dziedziczenie
Użycie klasy bazowej do utworzenia kolejnej (własnej) stanowi
proces dziedziczenia.
Użycie więcej niż jednej klasy bazowej do utworzenia kolejnej
(własnej) stanowi proces dziedziczenia wielokrotnego.
Class Student : private std::string, private std::vallarray<double>
{
Public:
…
};
Rekurencja
Wywołanie przez funkcję samej siebie stanowi rekurencję.
#include <iostream>
void countdown (int n);
int main()
{ countdown (4);
return 0; }
void countdown (int n);
{ using namespace std;
cout << ”Odliczanie …” << n << endl;
if (n>0)
countdown (n-1);
//wywołanie samej siebie
cout << n << ”. Zstępowanie. \n” ;
};