JĘZYKI PROGRAMOWANIA Z PROGRAMOWANIEM OBIEKTOWYM Wykład 5 1
SPECYFIKATOR const Specyfikator (przydomek) const: Umieszczenie przed nazwą zmiennej specyfikatora const w jej definicji informuje kompilator, że zawartość tej zmiennej nie może być modyfikowana. Zmienna taka (traktowana odtąd jako obiekt stały) musi być zainicjalizowana w momencie definicji. Inicjalizacja nadanie obiektowi (np. zmiennej) wartości w momencie jego tworzenia. Przypisanie podstawienie do obiektu wartości w dowolnym innym momencie. #include <iostream> using namespace std; int main() //const int MojaStala; //Błąd! Brak inicjalizacji const float MojaStala=5.123; cout<<mojastala; //MojaStala=6.456; //Błąd! Tego obiektu nie można zmieniać const int ROZMIAR=10; //pisanie obiektów stałych wielkimi literami int tablica[rozmiar]; //może zwiększać czytelność programu // (o tablicach później...) return 0; 2
TABLICE STATYCZNE Tablica jest to ciąg obiektów tego samego typu, które zajmują ciągły obszar w pamięci, np.: int t[5]; // statyczna tablica 5 obiektów typu całkowitego Numeracja elementów tablicy zaczyna się od zera!!! Np. piąty element tablicy ma indeks 4 Zatem mamy elementy: t[0], t[1], t[2], t[3], t[4] Wpisanie czegoś do elementu tablicy, który nie istnieje, np. t[5] nie jest sygnalizowane jako błąd! Może to powodować nadpisanie innych zmiennych! Rozmiar tak zdefiniowanej tablicy (tablica statyczna) musi być znany w momencie kompilacji. O tablicach dynamicznych w późniejszym czasie... 3
TABLICE STATYCZNE Tablice można tworzyć z: o typów fundamentalnych (z wyjątkiem void); o typów wyliczeniowych (enum); o innych tablic (tablice dwu- i wielowymiarowe); o wskaźników; a także: o obiektów typów zdefiniowanych przez użytkownika (obiektów klas); o wskaźników do pokazywania na składniki klasy. Zwykle korzysta się z pętli: int T[10]; for(int i=0; i<10; ++i) T[i]=i+3; //definiujemy tablicę //zauważ: i<10, czyli i=0..9 //wypełniamy tablicę wartościami for(int i=0; i<=9; ++i) //też prawidłowo, //ale mniej wygodnie... 4
TABLICE STATYCZNE Przykłady definicji tablic: int tablica1[20]; //tablica 20 liczb typu int int tablica2[3][4]; //tablica 12 liczb typu int int tablica3[2][3][4]; char zdanie[80]; float numery[20]; double liczby[5]; //tablica 24 liczb typu int //tablica 80 znaków typu char //tablica 20 liczb typu float //tablica 5 liczb typu double int *tabl_wsk[12]; Samochod tabl_ob[6]; //tablica 12 wskaźników do int //tablica 6 obiektów klasy Samochod o Indeks elementu tablicy musi być liczbą całkowitą lub wyrażeniem całkowitym. o Elementy tablic wielowymiarowych umieszczane są kolejno w pamięci komputera tak, że najszybciej zmienia się najbardziej skrajny prawy indeks. 5
TABLICE STATYCZNE Przykład tablica jednowymiarowa: #include <iostream> using namespace std; int main() const int ROZMIAR=10; //stała okreslająca rozmiar - zwiększa czytelność int T[ROZMIAR]; for(int i=0; i<rozmiar; ++i) //"i" jest znane tylko wewnątrz pętli for... T[i]=2*(i+1); cout<<t[i]<<" "; // cout<<endl <<i; //błąd kompilacji (patrz: poprzedni komentarz... return 0; 6
TABLICE STATYCZNE Przykład tablica dwuwymiarowa : #include <iostream> using namespace std; int main() const int W=2, K=3; //liczba Wierszy i Kolumn int Tabl[W][K]; cout<<"podawaj po kolei elementy tablicy: \n"; for(int i=0; i<w; ++i) //wpisywanie do tablicy 2-wymiarowej for(int j=0; j<k; ++j) cout<<"podaj element ["<<i<<"]["<<j<<"]: "; cin>>tabl[i][j]; cout<<endl<<"tablica zawiera elementy:\n"; for(int i=0; i<w; ++i) for(int j=0; j<k; ++j) //wypisywanie na ekran cout<<tabl[i][j]<<"\t"; // wypisanie i wstawienie tabulatora cout<<endl; //wstawienie znaku nowej linii na końcu wiersza return 0; 7
TABLICE STATYCZNE Nadawanie wartości elementom tablic: o w pętli (jak w przykładach): #include <iostream> using namespace std; int main() int Tablica[5]; for(int i=0; i<5; ++i) Tablica[i]=5*i; cout<<tablica[i]<<" "; return 0; o przypisanie każdego elementu z osobna, np.: int tab[3]; //tablica 3 liczb typu int tab[0]=1; tab[1]=4; tab[2]=-3 //jawne przypisanie 8
TABLICE STATYCZNE Nadawanie wartości elementom tablic: o inicjalizacja (zatem w momencie definicji tablicy), np.: int T1[5]=0; //wszystkie elementy zerowe int T2[5][3]=0; //wszystkie elementy zerowe int T3[6]=1; //pierwszy element równy 1, pozostałe zerowe int T4[5]=2,5,6; //elementy 4 i 5 zerowe (o indeksach 3 i 4) int T5[4]=1,2,3,4; //jawna inicjalizacja elementów int T6[2][2]=1,2,3,4; int T7[2][2]=1,3,4; //jawna inicjalizacja elementów //element T7[0][1] zerowy int T8[2][2]=1,2,3,4; //jawna inicjalizacja elementów int T9[ ]=1,2,3; //liczba elementów tablicy równa 3 int T10[3]=5,7,2,3; //błąd składni, za dużo elementów! 9
TABLICE STATYCZNE Nadawanie wartości elementom tablic: Brak zainicjalizowania elementów tablicy, która tego wymaga (np. zdefiniowanej w zakresie lokalnym) może powodować błąd logiczny (błąd wykonania), np.: #include <iostream> using namespace std; int main() const int ROZ=3; int tab[roz]; // definicja tablicy bez jej inicjalizacji // zapominamy o nadaniu wartości elementom... for (int i=0; i<roz; ++i) tab[i]+=i; //dodajemy coś do każdego elementu tablicy cout<<tab[i]<<" "; //i dostajemy niezamierzony rezultat... return 0; 10
TABLICE STATYCZNE Tablice znakowe: - to specjalne tablice, w których przechowywane są znaki (np. litery). Stringi (napisy) to ciągi znaków zakończone znakiem NULL (znak o kodzie 0) tego oczekują wszelkie funkcje biblioteczne operujące na stringach... char tekst1[30]; //tablica znakowa char char tekst2[30]= wyraz ; //znak NULL automatycznie dopisany char tekst3[ ]= wyraz ; //string poprawnie zakończony, jest NULL char tekst4[30]= w, y, r, a, z ; //reszta inicjalizowana //zerami, zatem jest znak NULL. char tekst5[]= w, y, r, a, z ; //nie ma znaku NULL! //nie jest to błąd, jeśli elementy tablicy nie mają być //traktowane jako string lecz osobne litery Niezapewnienie wystarczająco dużego rozmiaru tablicy znakowej do przechowania napisu może powodować utratę danych i poważne błędy wykonania! 11
FUNKCJE Funkcja: podprogram realizujący jakieś zadanie, który najczęściej jako rezultat zwraca jakąś wartość, np.: double pole_kwadratu(double a) //funkcja przyjmuje jako argument //dlugosc boku (typu double) return a*a; //i zwraca wartosc typu double Funkcję wywołuje się poprzez podanie jej nazwy i umieszczonych w nawiasie argumentów, np.: cout<<pole_kwadratu(3.5); o o o Każda funkcja przed użyciem musi być zadeklarowana. Nie można definiować funkcji wewnątrz innej funkcji (również main). Funkcja może wywoływać inną funkcję. double pole_kwadratu(double a); //sama deklaracja funkcji //(zauważ średnik na końcu) 12
FUNKCJE Przykład: #include <iostream> #include <cmath> using namespace std; double biegunowy(double d); // (tylko) deklaracja funkcji biegunowy // double biegunowy(double) //tak naprawdę tu wystarczy sam typ argumentu int main() //funkcja główna double srednica=10.2; cout << biegunowy(srednica) << endl; return 0; double biegunowy(double d) //a tu definicja funkcji biegunowy double wynik=m_pi*pow(d,4)/32; return wynik; Argumenty (parametry) formalne argumenty występujące w definicji funkcji (tu: d). Argumenty (parametry) aktualne argumenty użyte w wywołaniu funkcji (tu: srednica). 13
FUNKCJE Przykład: #include <iostream> #include <cmath> using namespace std; double biegunowy(double d) //Albo tak: //deklaracja i definicja funkcji biegunowy double wynik=m_pi*pow(d,4)/32; return wynik; int main() //funkcja główna double srednica=10.2; cout << biegunowy(srednica) << endl; return 0; Definicja funkcji jest deklaracją, w której przedstawiona jest treść tej funkcji Wywołanie funkcji zwracającej rezultat samo w sobie ma wartość, jaką ma rezultat zwracany przez tą funkcję, można je więc użyć w dowolnym wyrażeniu, np.: y=3.27+m+dodaj(2,3)+dodaj(n,5); 14
FUNKCJE Przykłady deklaracji funkcji: Deklaracja funkcji double dodaj(double a, double b); double dodaj(double, double); void wypisz(string napis); int fun11(void); int fun11(); Opis funkcja wywoływana z 2 argumentami typu double i zwracająca wartość typu double j.w. funkcja wywoływana z 1 argumentem typu string i nie zwracająca żadnej wartości funkcja wywoływana bez argumentów i zwracająca wartość typu całkowitego j.w. (inaczej, niż w C ) Jeśli funkcja nie zwraca żadnej wartości, to po słowie kluczowym return nie może stać żadna wartość (można też to słowo pominąć): void komunikat(int ile) cout<<"nalezy "<<ile<<" razy nacisnac Enter"; 15
FUNKCJE Funkcja main Specyficzne cechy: musi wystąpić w każdym programie; nie jest deklarowana; nie można jej wywołać z innej funkcji; tylko w niej można opuścić instrukcję return (kompilator sam doda return 0;) rezultatem działania może być wyłącznie liczba całkowita; tradycyjnie zwrócenie zera oznacza poprawne zakończenia działania (informacja dla systemu operacyjnego). 16
FUNKCJE Funkcje inline Krótkie funkcje można definiować jako inline ( w linii ). o Sugestia (która może być zignorowana) dla kompilatora, by w miejscu wywołania wstawić treść tej funkcji. o Skutek skrócenie czasu wykonania. o Definicja (nie tylko deklaracja) przed pierwszym wywołaniem tej funkcji (zwykle na początku programu lub w pliku nagłówkowym). 17
FUNKCJE Przykład: #include <iostream> using namespace std; inline void wypisz() //definicja funkcji inline cout<<" "<<endl; bool sprawdz(double a,double b) // zwykła funkcja wypisz(); //tu funkcja wywołuje inną funkcję if ((a*b)>0) return 1; else return 0; // zauważ przy okazji: return może występować więcej niż 1 raz int main() // funkcja główna double x,y; cout<<"podaj 2 liczby rozne od zera a powiem Ci, czy maja ten sam znak"; cout<<"\nliczba 1: "; cin>>x; cout<<"\nliczba 2: "; cin>>y; if (sprawdz(x,y)) cout<<"\nmaja ten sam znak"<<endl;//jesli wartość f. różna od 0 else cout<<"\nmaja rozne znaki"<<endl; //a jeśli równa zero... wypisz(); //wywołujemy funkcję wypisz() wewnątrz funkcji głównej return 0; 18
FUNKCJE Argumenty domyślne funkcji Programista może określić, że dany argument funkcji jest argumentem domyślnym i przypisać mu wartość domyślną. o o Argumenty domyślne muszą być położone najdalej z prawej strony na liście argumentów funkcji. Argumenty domyślne muszą być określone wraz z pierwszym wystąpieniem nazwy funkcji zazwyczaj w jej deklaracji (w późniejszej definicji już nie!). 19
FUNKCJE Przykład: #include <iostream> using namespace std; float odleglosc(int mm, int m=0, int km=0); // domyślne na końcu listy int main() cout.precision(10); cout<<odleglosc(10)<<" [mm]"<<endl; // wynik: 10 cout<<odleglosc(21,1)<<" [mm]"<<endl; // wynik: 1021 cout<<odleglosc(37,56,2)<<" [mm]"<<endl; // wynik: 2056037 //cout<<odleglosc()<<" [mm]"<<endl; //Błąd - pierwszy argument // nie jest domyślny! return 0; float odleglosc(int mm, int m, int km) //funkcja wylicza odleglosc w [mm] return mm+1000*m+1000*1000*km; 20
FUNKCJE Przekazywanie danych do funkcji przez wartość Przekazywanie argumentów do funkcji przez wartość powoduje, że funkcja pracuje na kopii przekazywanej zmiennej, więc nie ma możliwości jej modyfikowania. #include <iostream> using namespace std; int funkcja(int x) x=x*60; //albo: x*=60; return x; int main() int a=4, b; cout<<"a="<<a<<", b="<<b<<endl; // a=4, b=? //brak inicjalizacji zmiennej! b=funkcja(a); cout<<"a="<<a<<", b="<<b<<endl; // a=4, b=240 //a nadal równe 4 return 0; O innych sposobach przekazywania danych do funkcji (przez referencję i przez wskaźniki) na innym wykładzie 21
FUNKCJE Przeładowanie (przeciążanie) nazwy funkcji: o o o Sytuacja, gdy w tym samym zakresie ważności jest więcej niż jedna funkcja o takiej samej nazwie. Funkcje te muszą się różnić typem i/lub liczbą argumentów wywołania. Zatem mogą współistnieć w danym zakresie ważności np. funkcje: float oblicz(float x); int oblicz(int x); float oblicz(int x, float y); int oblicz(int x, int y); int oblicz(int zmienna); //Błąd! Już jest taka funkcja! 22
FUNKCJE Przykład: #include <iostream> using namespace std; //------------------------------------------------------------------- void sprawdz(int x) // pierwsza funkcja sprawdz() if (!x) cout<<"sprawdzana liczba to zero\n"; else cout<<"sprawdzana liczba to nie jest zero\n"; //------------------------------------------------------------------- void sprawdz(float x, float y) // druga funkcja sprawdz() if (x>y) cout<<"pierwsza liczba jest wieksza niz druga\n"; else cout<<"pierwsza liczba nie jest wieksza niz druga\n"; //------------------------------------------------------------------- bool sprawdz(char aa) // trzecia funkcja sprawdz() if (aa=='x') cout<<"to jest 'x'"<<endl; return 1; else cout<<"to nie jest 'x'"<<endl; return 0; //------------------------------------------------------------------- int main() // funkcja główna int calkowita=5; float a=5.1, b=4.2; char znak='y'; sprawdz(calkowita); sprawdz(a,b); sprawdz(znak); return 0; 23
WYRAŻENIE WARUNKOWE Wyrażenie warunkowe ma postać: warunek? wartość1 : wartość2 np.: (wiek>=18)?1:0; Jeśli warunek jest spełniony to wartość wyrażenia wynosi wartość1. W przeciwnym przypadku wartość wyrażenia wynosi wartość2. Wyrażenie warunkowe może być składnikiem innych wyrażeń: cout<<"ten produkt "; (wiek>=18)?cout<<"moze ":cout<<"nie moze "; cout<<"byc Ci sprzedany"<<endl; 24
WYRAŻENIE WARUNKOWE #include <iostream> using namespace std; int main() float a; cout<<"\n Podaj dowolna liczbe a powiem Ci, czy jest wieksza niz 5.1"<<endl<<" "; cin>>a; cout<<" Podana przez Ciebie liczba "; (a>5.1)?cout<<"jest ":cout<<"nie jest "; //wyr. warunkowe cout<<"wieksza niz 5.1"<<endl; return 0; 25