Programozás II. 4. Dr. Iványi Péter
1
inline függvények • Bizonyos függvények annyira rövidek, hogy nem biztos hogy a fordító függvényhívást fordít, hanem inkább az adott sorba beilleszti a kódot. #include
using namespace std;
#include using namespace std;
inline int max(int a, int b) { return ((a > b) ? a : b); } int main() { cout << max(10,20); return 0; }
int main() { cout << ((10 > 20) ? 10 : 20); return 0; } 2
inline függvények • inline esetén nincs verem művelete – Paraméter átadás, visszatérési érték
• Növeli a kód méretét, hiszen sok az ismétlés – Csak kis méretű kódot érdemes beilleszteni
• Csak egy kérés, a fordító nem biztos hogy megteszi • Osztályok esetén eddig is ezt használtuk – Gyorsabb kód, de a használó látja mi történik • Csak a nagyon kicsi, legbiztosabb részeket érdemes inlineolni 3
static kulcsszó C-ben #include <stdio.h> int osszegez(int a) { static int allapot = 0; allapot += a; return allapot; } int main() { osszegez(1); osszegez(2); printf(”%d”, osszegez(3)); return 0; }
6 4
#include using namespace std; class osztott { static int a; int b; public: void set(int i, int j) { a=i; b=j;} void show() { cout << "Static: " << a << "nem static: " << b << endl; } }; int osztott::a = 0; int main () { osztott x, y; x.set(1,1); x.show(); y.set(2,2); y.show(); x.show(); return 0; }
Static: 1 nem static: 1 Static: 2 nem static: 2 Static: 2 nem static: 1 5
static kulcsszó • Az osztályon belül csak deklaráljuk, de mivel több osztály is megosztja ezért a konkrét definíció osztályon kívül kell legyen, a globális értelmezési tartományban • Hivatkozni lehet rá: – Mint konkrét objektum elemeként: cout << a.n – Mint osztály részeként: cout << szam.n
• Ezek tulajdonképpen globális változók!!!
6
#include using namespace std; class osztott { public: static int a; };
static kulcsszó Többféle hivatkozás
int osztott::a = 0; int main () { osztott::a = 99; cout << "A értéke:" << osztott::a << endl; osztott x; cout << "A értéke:" << x.a << endl; return 0; }
7
using namespace std; static kulcsszó #define FOGLALT 1 #define SZABAD 0 Erőforrás kontrol, egyszerre csak class valami { egy objektum használja static int eroforras; public: int get_res() { if(eroforras) return 0; else { eroforras=FOGLALT; return 1;} } void free_res(){ eroforras=SZABAD; } }; int valami::eroforras=0; int main () { valami a, b; if(a.get_res()) cout << "Megvan\n"; else cout << "Nincs\n"; Megvan if(b.get_res()) cout << "Megvan\n"; else cout << "Nincs\n"; Nincs a.free_res(); if(b.get_res()) cout << "Megvan\n"; else cout << "Nincs\n"; Megvan return 0; } 8
#include using namespace std; class szam { public: static int n; szam () { n++; }; ~szam () { n--; }; }; int szam::n=0; void f() { szam a; cout << szam::n << endl; } int main () { szam a; szam b[5]; cout << szam::n << endl; f(); cout << szam::n << endl; return 0; }
static kulcsszó Hány darab objektum létezik
// 7
// 6 // 6
9
Barátok, friend • Lehetőség van arra, hogy egy olyan függvény férjen hozzá egy osztály privát változóihoz, amley nem tagfüggvénye az osztálynak – friend függvények
• Hol használjuk: – Operátor overloading esetén – Bizonyos I/O esetén
10
#include using namespace std; class valami { int a, b; public: friend int sum(valami x); void set_ab(int i, int j) { a=i; b=j; } }; int sum(valami x) { return(x.a + x.b); }
// a függvény nem része az osztálynak !!!!
void main() { valami n; n.set_ab(2,3); cout << sum(n) << endl; } 11
Friend függvények • Két különböző osztály • Mind a kettő megjelenít egy üzenet ablakot • A program többi tudni szeretné hogy látható-e egy ablak, mert akkor nem üzennek
12
#include using namespace std; #define SZABAD 0 #define FOGLALT 1 class C1; class C1 { int status; ... public: void set_status(int s) { status=s; } friend int szabad(C1 a, C2 b); }; class C2 { int status; ... public: void set_status(int s) { status=s; } friend int szabad(C1 a, C2 b); }; 13
int idle(C1 a, C2 b) { if(a.status || b.status) return 0; else return 1; } void main() { C1 x; C2 y; x.set_status(SZABAD); y.set_status(SZABAD); ... if(idle(x,y)) ... x.set_status(FOGLALT); } 14
Friend függvények • Az egyik osztály függvénye lehet friend függvénye egy másik osztálynak • Egy osztály is lehet barátja egy másik osztálynak – A friend osztály minden privát változóhoz hozzáfér!!
15
Objektumok • Egymáshoz rendelhetők, értékadás • Lehetnek függvények visszatérési értékei • Lehetnek függvények argumentumai
16
Egy furcsaság • Objektumokat egyszerűen át lehet adni függvényeknek, de ...
17
#include using namespace std; class valami { int a; public: valami(int n) { a=n; cout << "Konstruktor " << a << endl; } ~valami() { cout << "Destruktor " << a << endl; } void set_a(int n) { a=n; } int get_a() { return a; } };
18
void f(valami o) { o.set_a(2); cout << "Lokalis a: " << o.get_a() << endl; } void main() { valami ob(1); f(ob); cout << "in main a: " << ob.get_a() << endl; }
19
Az eredmény Konstruktor 1 Lokalis a: 2 Destruktor 2 in main a: 1 Destruktor 1
innen hiányzik egy konstruktor
Amikor argumentumként adjuk át az objektumot a normális konstruktor nem hívódik meg, helyette egy másoló konstruktor hívódik meg. (Erről egy kicsit később lesz szó.)
20
#include using namespace std; class valami { int a; public: void set_a(int n) { a=n; } int get_a() { return a; } }; valami f() { valami x; x.set_a(1); return x; }
void main() { valami o; o = f(); cout << o.get_a() << endl; }
Bitenkénti másolás
Függvény visszatérési értéke is lehet objektum 21
Objektumok értékadásban #include using namespace std; class valami { int a; public: void set_a(int n) { a=n; } int get_a() { return a; } }; void main() { valami ob1, ob2; ob1.set_a(2); ob2 = ob1; cout << ob2.get_a() << endl; }
Bitenkénti másolás 22
Másoló konstruktor • Alap esetben bitenként másol • Nincs is gond amíg nem egy pointert másol le – Emlékezzünk minden objektumnak külön adatai vannak
• A többi egy kicsit később
23
Objektum tömbök • Objektumokból is lehet tömböt készíteni • Szintaxis ugyanaz! • Egy paraméteres konstruktor esetén mint C-ben, egyébként csak a konstruktor meghívásával lehet inicializálni
24
#include using namespace std; class valami { int a; public: void set_a(int n) { a=n; } int get_a() { return a; } }; void main() { valami ob[3]; int j; for(j=0;j<3;j++) ob[j].set_a(j+1); for(j=0;j<3;j++) cout << ob[j].get_a() << endl; } 25
#include using namespace std; class valami { int a; public: valami(int n) { a=n; } int get_a() { return a; } }; void main() { valami ob[3] = {1,2,3}; int j; for(j=0;j<3;j++) cout << ob[j].get_a() << endl; } 26
#include using namespace std; class valami { int a; public: valami(int n) { a=n; } int get_a() { return a; } }; void main() { valami ob[3] = {valami(1), valami(2), valami(3)}; int j; for(j=0;j<3;j++) cout << ob[j].get_a() << endl; } 27
#include using namespace std; class valami { int a; public: valami(int n) { a=n; } int get_a() { return a; } }; void main() { valami a[4]; // érvénytelen int j; for(j=0;j<3;j++) cout << ob[j].get_a() << endl; } 28
#include using namespace std; class valami { int a; public: valami(int n) { a=n; } valami() { a=0; } int get_a() { return a; } }; void main() { valami a[4]; // érvényes !!! int j; for(j=0;j<3;j++) cout << ob[j].get_a() << endl; } 29
Memória kezelés • Fortran-ban: int tomb[1000];
• C-ben: malloc, free
• C++ -ban: new, delete operátorok Több előnye is van az új operátoroknak
30
new és delete • new: lefoglalja a memóriát és visszaad egy mutatót, mely a területre mutat – Ha nincs elég memória kivételt dob (erről később)
• delete: felszabadítja a lefoglalt memóriát – Csak a new-al foglalt memóriánál használjuk p_var = new típus; ... delete p_var; 31
new és delete • Előnyök: – Nem kell megmondani a lefoglallandó objektum méretét • sizeof operátor nem kell, nem is hibázhatunk
– Mindig a megfelelő típusú mutatót adja vissza nem kell cast-olni • void *malloc(int size);
– Mindkettő „felüldefiniálható”
32
#include using namespace std;
void main() { int *p; // a memória inicializálása p = new int (87); cout << *p << endl; delete p; }
33
Tömb lefoglalása p_var = new tömb_típus [méret]; ... delete [] p_var;
• Tömböket nem lehet inicializálni !!!!!
34
#include using namespace std;
void main() { int *p, j; // a memória inicializálása p = new int [10]; for(j=0; j < 10; j++) p[j] = j; for(j=0; j < 10; j++) cout << p[j] << " "; delete [] p; } 35
Dinamikus objektumok • A new és delete segítségével objektumokat is lehet dinamikusan kezelni!!!
36
#include #include <string> using namespace std; class szamla { double ertek; string nev; public: void set(double e, string n) { ertek=e; nev=n; } double get_ertek() {return ertek;} string get_nev() {return nev;} }; void main() { szamla *p; p = new szamla; p->set(1234.56, "Kovacs Istvan"); cout << p->get_nev() << " " << p->get_ertek() << endl; delete p; }
37
#include #include <string> using namespace std; class szamla { double ertek; string nev; public: szamla(double e, string n) { ertek=e; nev=n; } double get_ertek() {return ertek;} string get_nev() {return nev;} }; void main() { szamla *p; p = new szamla(1234.56, "Kovacs Istvan"); cout << p->get_nev() << " " << p->get_ertek() << endl; delete p; } 38
#include #include <string> using namespace std;
Dinamikus objektum tömb esetén kell egy paraméter nélküli konstruktor
class szamla { double ertek; string nev; public: szamla() { ertek=0; nev="Ismeretlen"; } szamla(double e, string n) { ertek=e; nev=n; } void set(double e, string n) { ertek=e; nev=n; } double get_ertek() {return ertek;} string get_nev() {return nev;} };
39
void main() Paraméter nélküli konstruktort hívja { szamla *p; int j; p = new szamla[3]; for(j = 0; j < 3; j++) cout << p[j].get_nev() << " " << p[j].get_ertek() << endl; p[0].set(1111, "Alma Rozsa"); p[1].set(2222, "Korte Bela"); p[2].set(3333, "Szilva janos"); for(j = 0; j < 3; j++) cout << p[j].get_nev() << " " << p[j].get_ertek() << endl;
meg
delete [] p; }
40