270 likes | 397 Views
Ra čunarski praktikum 1 Vježbe 7. Zvonimir Bujanović Vinko Petričević. Ugnje žđene strukture. strukture mogu sadržavati i druge strukture. struct stogStringova { ... }; struct A utomobil { string registracija; stogStringova vlasnici; int godina P roizvodnje; } ;.
E N D
Računarski praktikum 1Vježbe 7 Zvonimir Bujanović Vinko Petričević
Ugnježđene strukture • strukture mogu sadržavati i druge strukture struct stogStringova { ... }; struct Automobil { string registracija; stogStringova vlasnici; int godinaProizvodnje; };
Ugnježđene strukture: konstruktor • ako neki element strukture nema defaultni konstruktor (bez parametara), potrebno ga je navesti u konstruktoru strukture struct stogStringova{ stogStringova(int velicina) ... }; struct Automobil { stogStringova vlasnici; Automobil() :vlasnici(5) {...} Automobil(int maxVl):vlasnici(maxVl){} };
Ugnježđene strukture: drugi pristup • ponekad struktura članica ima smisla samo unutar veće strukture struct Automobil { struct Motor { int snaga; double obujam; Motor (int s, double o) { snaga = s; obujam = o; } }; Motor m; int brojVrata; Automobil() : m(90, 1.4) { ... } Automobil(int s, double o) : m(s, o) { ... } };
Ugnježđene strukture: drugi pristup • možemo svejedno deklarirati i varijable tipa Motor: Automobil yugo(45, 1.2); Motor tdi(120, 1.9); // krivo! Automobil::Motor turboDiesel(120, 1.9); // OK yugo.m = turboDiesel; cout << yugo.m.snaga; cout << yugo.brojVrata;
Zadatak 1 • Napravite implementaciju atp-a list pomoću polja; lista treba moći čuvati max. 100 elemenata proizvoljnog tipa • Struktura treba sadržavati i tip podatka iterator tako da se može raditi sljedeće: • uputa: neka iterator sadrži pokazivač na tip list<int> L; L.push_back(5); L.push_back(7); list<int>::iterator li = L.begin(); while (!li.isEqual(L.end())) { cout << li.data() << “ “; li = li.next(); }
const varijable • svaki tip podatka koji smo do sada susretali, može biti i const-tip (njegov sadržaj je moguće samo čitati). • const varijable se moraju inicijalizirati: • konverzija s “normalnog” u const tip je moguća, ali obrnuta ne: const int a; // krivo! const int b = 5; // OK const int a = 5; int b = 3; a = b; // krivo! b = a; // OK
const pointeri • u deklaraciji konstantno je ono na što pokazuje s, a ne i sama varijabla s. Dakle: const char*s = “rp1”; char*s1 = “abc”; const char *s = “rp1”; s[1] = ‘A’; // greska, mijenjam ono na sto pok. s s1 = s; // greska,preko s1 bi se mogao mijenjati s! s = s1; // OK s[1] = ‘A’; // i dalje greska s1[1] = ‘A’; // OK
const varijable • const nam koristi da zabranimo izmjenu nekih stvari u strukturama koje kreiramo • Npr. string::c_str() vraća const char* • slično: operator* na set<T>::iterator vraća const T, budući da bi mijenjanje vrijednosti uništilo uređenje strukture void ispis(char*s) {...} void ispis1(const char*s) {...} string s; ispis(s.c_str()); // greška ispis1(s.c_str()); // OK
const funkcije članice • Funkcije članice koje ne modificiraju objekt moguće je deklarirati kao const funkcije (u tom slučaju ih je onda moguće pozivati i na const objektima) struct MyString{ char *data; int duljina; MyString() { ... } MyString(const char *s) { ... } int length() const{ ... } const char *c_str() const{ ... } }; const MyString s; // ok, init je konstruktor! int i=s.length(); // OK jer je i length const
Reference • ako funkcija treba promijeniti varijablu koju joj šaljemo kao parametar, onda u C-u tu varijablu treba slati kao pointer: void f ( int *p ) { *p = 3; } int main() { int x = 5; f(&x); cout << x; // ispisuje 3 return 0; }
Reference • u C++-u osim pointera i “običnih varijabli” postoje i reference – to su varijable koje se ponašaju kao pointeri, a s njima radimo kao sa “običnim varijablama” (bez * i &) • referenca uvijek mora biti inicijalizirana: int a=5, b=3; int &r = a; // OK, r je referenca na a int &t = 5; // krivo! nema varijable int &s; // krivo! nema varijable cout << r; // ispisuje 5 r = b; // u r(tj. u a) napisi vrijednost od b cout << r << “ “ << a; // ispisuje 3 3
Reference • reference se ponašaju kao pointeri: int a=5; int &r = a; cout << a; // ispisuje 5 r = 7; cout << a; // ispisuje 7 void f (int &a) { a = 7; } int main() { int x = 5; f(x); cout << x; // ispisuje 7 }
Reference • const reference – ne može se mijenjati ono na što referiraju: • funkcijama se često šalje const referenca. Zašto? • zašto copy-konstruktor prima referencu, a ne “običnu varijablu” i zašto je ta referenca const? int a=5; const int &r = a; cout << r; // ispisuje 5 r = 7; // krivo! r je const referenca a = 7; // ok, a nije const varijabla cout << r; // ispisuje 7
Reference • funkcija može vraćati referencu: • što bi se dogodilo da funkcija nije primila referencu, već “običnu varijablu”? int &prviElementVektora(vector<int> &V) { return V[0]; } int main () { vector<int> V(10); cout << V[0]; // ispise 0 prviElementVektora(V) = 5; // OK!!! cout << V[0]; // ispise 5 }
Reference • oprez: ne smijemo vraćati referencu na lokalnu varijablu u funkciji! int &proba(int *a) { int temp = 5; *a = 5; return temp; // krivo (warning), temp je lok.! return *a; // ok, a živi i van proba } int main () { int x = 3; int y = proba(&x); // OK, y = 5; int &t = proba(&x); // OK t++; cout << x; // ispise 6 }
this pointer • kad pozivamo funkciju članicu, kako funkcija “zna” sa kojim smo je objektom pozvali? • odgovor: implicitno se funkciji zapravo šalje adresa objekta koji ju poziva stack S, T; S.push(5); T.push(5); struct stack { ... void push(int x); }; stack S, T; push(&S, 5); push(&T, 5); void push (stack *S, int x) { S->podaci[S->vrh++] = x; }
this pointer • unutar svake funkcije članice postoji varijabla this koja sadrži adresu od objekta koji je pozvao funkciju struct stack { void push( int x ) { this->podaci[this->vrh] = x; this->vrh++; } };
this pointer • na ovaj način moguće je vratiti referencu na sam objekt, što je ponekad korisno struct stack { stack &push( int x ) { podaci[vrh++] = x; return *this; } }; int main () { stack S; S.push(5).push(7).push(8); // OK! }
static varijable • Statički podaci su smješteni u kôdu (kao i globalne varijable), i inicijaliziraju se samo jednom void f() { static int i=0; cout<<++i; } void f1() { static int i=0; cout<<++i; } ... f(); // ispiše 1 f(); // ispiše 2 f1(); // ispiše 1 f1(); // ispiše 2
static varijable • Kreiraju se prilikom prvog korištenja, a uništavaju (ako su bile kreirane) na kraju izvršavanja programa. struct S { S() { cout<<“Kreiran S”<<endl; } ~S() { cout<<“Unisten S”<<endl; } }; void f() { static S s; } int main() { cout<<“Poceo program”<<endl; f(); cout<<“Zavrsio program”<<endl; return 0; }
static elementi strukture • zajednički su za sve objekte nekog tipa • ne zauzimaju memoriju na heapu/stacku • moraju biti ‘inicijalizirani’ izvan svih funkcija struct MyStruct{ static int brojZivihStruktura; MyStruct() { brojZivihStruktura++;} ~MyStruct() { brojZivihStruktura--; } }; int MyStruct::brojZivihStruktura = 0; int main() { MyStruct a, b, c; cout << MyStruct::brojZivihStruktura; return 0; }
Zadatak 2 • Nadopunite definiciju strukture sa prethodnog slide-a tako da osim broja trenutno živih objekata tipa MyStruct ona održava i popis (listu) svih tih objekata • uoči: popis mora sadržavati pointere ili reference. Što bi se dogodilo da se u popisu nalaze samo MyStruct-ovi?
static funkcije članice • static funkcije mogu pristupati samo static članovima strukture (nemaju this) • možemo ih pozivati i direktno (bez varijable) struct MyStruct{ static int brojStruktura; int brojac; MyStruct() { brojac = brojStruktura++; } static int broj() { return brojac; // greska, brojac nije static return brojStruktura; // OK } }; int i = MyStruct::broj(); // MyStruct s; int i=s.broj();
extern • Ako istu varijablu koristimo u više .cpp datoteka (koje zajedno linkamo), trebamo navesti da je ona extern. // neki.h extern int zajednicka_varijabla; // u samo jednom .cppu int zajednicka_varijabla;
Pretpostavljeni parametri funkcija • Svi ili nekoliko zadnjih parametara funkcije mogu imati postavljene defaultne vrijednosti void f(int a, string b=“netko”) { cout <<b<<“ ima “<<a<<“godina”; } int main () { f(20, “Mirko”); // Mirko ima 20 godina f(19); // netko ima 19 godina }
Pretpostavljeni parametri funkcija • oprez, lako može doći do dvosmislenosti! struct MyStruct { MyStruct() { ... } MyStruct(int a=5) { ... } }; MyStruct a; // krivo: koji konstruktor? MyStruct b(7); // OK