Progrmozás lpji II. (4. e) C++ konstruktor és értékdás, dinmikus szerkezetek Szeberényi Imre BME IIT <szebi@iit.bme.hu> M Ű E G Y T E M 1 7 8 2 C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -1- Hol trtunk? C C++ jvítások OO prdigmák, objektum foglm A C++ csupán eszköz: objektum megvlósítás osztály (egységbe zár, és elszigetel), konstruktor, destruktor, tgfüggvények lpértelmezett operátorok, és tgfüggvények operátor átdefiniálás (függvény átdefiniálás) Elegendő eszköz vn már kezünkben? C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -2- Konstr: létrehoz+inic. (ism.) double re, im; Komplex() { re = 0; im = 0; Komplex(double r) { re = r; im = 0; Komplex(double r, double i) { re = r; im = i;... ; Komplex k; // defult Komplex k1(1); // 1 prméteres Komplex k2(1, 1); // 2 prméteres Inicilizáló list clss Vlmi { const double c1 = 3.14; // inicilizálni kell, de hogyn? Komplex k1; Vlmi(double c) { c1 = c Vlmi(double c) :c1(c) { Vlmi(double c, Komplex k) :c1(c), k1(k) { ; Konstns tg, és referenci tg, csk inicilizáló listávl inicilizálhtó. Célszerű tgváltozókt is inicilizáló listávl inicilizálni (felesleges műveletek elkerülése). C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -3- C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -4- Destruktor: megszüntet (ism.) ; String(const chr *s = "") { p = new chr[(size = strlen(s)) + 1]; // terület fogllás strcpy(p, s); ~String() { delete [] p; // fogllt terület felsz. ; A p és size megszüntetése utomtikus, hogy egy lokális változó is megszűnik. A new-vl fogllt dinmikus terület felszbdítás zonbn mi feldtunk. C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -5- Konstns tgfüggvények double re, im; Komplex(double r = 0, double i = 0) : re(r), im(i) { double Re() const { return(re); double Im() const { return(im); double Abs() const; ; double Komplex::Abs() const { return(sqrt(re*re + im*im)); Nem változtthtj meg z állpotot (dtokt) C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -6-1
Alpértelmezett tgfüggvények Konstruktor defult: X() // nincs prmétere másoló: X(const X&)// referenci prméter opertor=(const X&) // értékdó opertor&() // címképző opertor,(const X&) // vessző A másoló konstruktor és z értékdó operátor lpértelmezés szerint meghívj z dttgok megfelelő tgfüggvényét. Alptípus esetén bitenként másol! C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -7- Péld: Intelligens string String tárolásár lklms objektum, mi csk nnyi helyet fogll memóriábn, mennyi feltétlenül szükséges. dinmikus dtszerkezet Műveletei: létrehozás, megszüntetés indexelés: [] másolás: = összehsonlítás: == összefűzés: (String + String), (String + chr) (chr + String) kiírás: cout << beolvsás: cin >> C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -8- int size String dtszekezete C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -9- H E L L O dinmikus memóri (hep) ; A String osztály ; Ez defult konstruktor is String(const chr *s = "") { p = new chr[(size = strlen(s)) + 1]; strcpy(p, s); ~String( ) { delete[] p; chr& opertor[] (int i) { return p[i]; Itt nem fontos, de... C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -10- Függvényhívás mint blérték Értékdás problémáj min ( ) { chr c; String s( "Üdvözöllek dicső lovg" ); c = s[3]; // c = s.opertor[](3); c=p[3]; s[2]=''; // s.opertor[](2) =' '; p[2]=''; // destruktor: delete[] p { String s1( bj ), s2( vn! ); s1 s2 int size = 4 b j v n! C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -11- C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -12-2
Értékdás problémáj/2 { String s1( bj ), s2( vn! ); s1 s2 s2 = s1; // destruktor bj -r 2x, vn -r 0x C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -13- b j v n! Prméterként kpj zt, mit értékül kell dni egy létező objektumnk. String& opertor=(const String& s) { // s1=s2=s3 mitt ; Megoldás: operátor= átdefiniálás if (this!= &s ) { // s = s mitt delete[] p; p = new chr[(size = s.size) + 1]; strcpy(p, s.p); return *this; // visszdj sját mgát C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -14- Kezdeti értékdás problémáj Megoldás: másoló konstruktor { String s1( bj ); String s2 = s1; s1 s2 // destruktor bj -r 2x C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -15- b j Referenciként kpj zt példányt, mit lemásolv létre kell hozni egy új objektumot. String(const String& s) { p = new chr[(size = s.size) + 1]; strcpy(p, s.p); C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -16- Miért más mint z értékdás? A kezdeti értékdáskor még inicilizáltln változó (nem létezik), ezért nem lehet másolássl zonos módon kezelni. Mikor hívódik másoló konstruktor? inicilizáláskor (zonos típussl inicilizálunk) függvény prméterének átdáskor függvény vissztérési értékének átvételekor ideiglenes változók összetett kifejezésekben kivétel átdáskor C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -17- Függvényhívás és vissztérés Hívás String s0, s1; s1 = f (s0); tmp s0 -> s (verem) r -> tmp Hívott String f ( String s ) { String r;... return r; r, s C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -18-3
Összetett lgebri kifejezés String s, s0, s1, s2; s = s0 + s1 + s2; 1. lépés: tmp1=s0+s1 2. lépés: 3. lépés: 4. lépés: tmp2=tmp1+s2 s = tmp2 tmp1, tmp2 megszüntetése destruktor hívássl String rejtvény ; min( ) { String s1("rejtvény"); String s2; String( ); // 1 String s3 = s2; String(chr *); // 2 String(String&); // 3 chr c = s3[3]; ~String( ); // 4 s2 = s3; String opertor+(string&); // 5 s2 = s3 + s2 + s1 chr& opertor[](int); // 6 String& opertor=(string&);// 7 // destr. ; 2 1 3 6 7 5,3,5,3, (3),7,4,4,(4) 4,4,4 C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -19- C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -20- ; String( ); // 1 String(chr *); // 2 String(String&); // 3 ~String( ); // 4 String opertor+(string&); // 5 chr& opertor[](int); // 6 String& opertor=(string); // 7 ; String rejtvény/2 min( ) { String s1("rejtvény"); 2 String s2; 1 String s3 = s2; 3 chr c = s3[3]; 6 s2 = s3; 3,7,4 s2 = s3 + s2 + s1 5,3,5,3, (3),7,4,4,(4) // destr. 4,4,4 Miért referenci? Miért kell referenci másoló konstruktorhoz? A prméterátdás definíció szerint másoló konstruktort hív. H másoló konstruktor nem referenciát, hnem értéket kpn, kkor végtelen ciklus lenne. C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -21- C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -22- Miért fontos delete[]? String *st = new String[3]; st[0] st[1] st[2] int size = 0 int size = 0 int size = 0 A delete st htásár csk *st, zz z st[0] destruktor hívódik meg! Az st[1] és z st[2] áltl fogllt memóri nem szbdul fel! A delete[] meghívj minden elem destruktorát. C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -23- Védelem enyhítése Nem tgfüggvény! String + String opertor+(string& s); String opertor+(chr c); friend String opertor+(chr c, String s); ; String opertor+(chr c, String s) { = new chr[s.size + 2]; *p = c; strcpy (p+1, s.p); String sr(p); delete[] p; return(sr); C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -24-4
Keletkezett-e +=? Az lptípusokr meghtározott műveletek közötti logiki összefüggések nem érvényesek szármzttott típusokr. Azz z opertor= és z opertor+ meglétéből nem következik z opertor += H szükség vn rá, definiálni kell. Változtthtó viselkedés Feldt: "Vrázsütésre" z összes String csup ngybetűvel írjon ki! Megoldás: viselkedést befolyásoló jelző, de hol? objektum állpot (dt) csk z dott példányr vn htás. globális változó elég rond megoldás! z osztályhoz rendelt állpot: sttikus tg ill. tgfüggvény. C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -25- C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -26- Sttikus tg Az osztálybn sttikusn deklrált tg nem példányosodik. Pontosn egy példány létezik, mit explicit módon definiálni kell (létre kell hozni). Minden objektum ugynzt tgot éri el. Nem szükséges objetumml hivtkozni rá. pl: String::SetUcse(true); Sttikus tgként z osztály trtlmzhtj önmgát. Felhsználás: globális változók elrejtése String sttikus tggl ; sttic bool ucse; // sttikus tg deklrálás sttic bool SetUcse(bool b = true) { bool prev = ucse; ucse = b; return (prev); friend ostrem& opertor<<(ostrem& os, String& s); ; bool String::ucse = flse; // FONTOS: létre kell hozni!! C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -27- C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -28- String sttikus tggl /2 ostrem& opertor<<(ostrem& os, String& s) { for (i = 0; i < s.size; i++) { chr ch = s.ucse? toupper(s.p[i]) : s.p[i]; os << ch; // miért kell ch? return os; Osztályhoz trtozik, nem példányhoz Komplex péld újból Olvssunk be dott/tetszőleges számú komplex számot és írjuk ki számokt és bszolút értéküket fordított sorrendben! Objektumok: Komplex, KomplexTr konstruktorbn dott méret (, változt) igény szerint változttj méretét (b, változt) Mindkét megoldás dinmikus memórikezelést igényel. Ügyelni kell helyes felszbdításr, fogllásr. C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -29- C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -30-5
KomplexTr osztály clss KomplexTr { Komplex *t; // pointer dinmikusn fogllt tömbre int db; // tömb mérete (elemek szám) clss Tr_Hib {; // osztály z osztálybn hibkezeléshez KomplexTr(int m = 10) :db(m) { t = new Komplex[m]; // konstruktor (def = 10) KomplexTr(const KomplexTr& kt);// másoló konstruktor Komplex& opertor[](int i); // indexelés KomplexTr& opertor=(const KomplexTr& kt); // értékdás ~KomplexTr() { delete[] t; // felszbdítás ; C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -31- KomplexTr osztály/2 KomplexTr::KomplexTr(const KomplexTr& kt) {//másoló konst. t = new Komplex[db = kt.db]; for (int i = 0; i < db; i++) t[i] = kt.t[i]; // miért nem memcpy? A memcpy nem hívná meg konstruktort KomplexTr& KomplexTr::opertor=(const KomplexTr& kt) {// = if (this!= &kt) { delete[] t; t = new Komplex[db = kt.db]; for (int i = 0; i < db; i++) t[i] = kt.t[i]; // miért nem memcpy? return *this; Visszvezettük értékdásr KomplexTr::KomplexTr(const KomplexTr& kt){//másoló 2.vált. t = NULL; *this = kt; // trükkös, de rendben vn! C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -32- Indexelés és főprogrm (,) Komplex& KomplexTr::opertor[](int i) { if (i >= db i < 0) throw Tr_Hib(); return t[i]; int min() { KomplexTr t(5); // tárolóbn 5 elemünk vn try { for (int i = 0; i < 20; i++) cin >> t[i]; // beolvsás KomplexTr t2 = t1; // másoló konstruktor for (i = 19; i >= 0; i--) cout << t[i] ' ' << (double)t[i] << endl; // kiirás ctch (KomplexTr::Tr_hib) { cerr << "Indexelesi hib\n"; // hibkezelés return(0); C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -33- Változó méretű KomplexTr (b,) // Indexelés htásár növekszik méret, h kell Komplex& KomplexTr::opertor[](int i) { if (i < 0) throw Tr_Hib(); // hibás indexelés if (i >= db) { // növekednie kell, célszerű kvntumokbn Komplex *tmp = new Komplex[i+10]; // legyen ngyobb for (int j = 0; j < db; j++) tmp[j] = t[j]; // átmásol delete[] t; // régi törlése t = tmp; // pointer z új területre db = i + 10; // megnövelt méret return t[i]; // referenci vissz C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -34- Összefogllás /1 INICIALIZÁLÁS!= ÉRTÉKADÁS Inicilizáló list szerepe. Alpértelmezett tgfüggvények. Dinmikus szerkezeteknél ngyon fontos másoló konstruktor és z értékdás felüldefiniálás. (nem mrdht lpért.) Defult konstruktornk fontos szerepe vn tömböknél. Egyprméterű konstruktor utomtikus konverzió. C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -35- Összefogllás /2 Konstns tgfüggvények nem változttják z objektum állpotát. Sttikus tg és tgfüggvény z osztályhoz trtozik. Védelem enyhítése: friend Létrehozás, megsemmisítés feldtit konstruktor és destruktor látj el. C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -36-6
Létrehozás, megsemmisítés Konstruktor defult: X() // nincs prmétere utomtikusn létrejön, h nincs másik konst. másoló: X(const X&) // referenci prmétere vn, utomtikusn létrejön: meghívj z dttgok másoló konst.-rát, h objektumok, egyébként bitenként másol. Destruktor delete[ ] // [ ] nélkül csk 0. tömbelemre!! utomtikusn létrejön: meghívj z dttgok destr. opertor=(const X&) // értékdó operátor utomtikusn létrejön: meghívj z dttgok értékdó operátorát, h objektumok, egyébként bitenként másol. Milyen furcs kommentek! A kommentekből utomtikusn generál dokumentációt Doxygen progrm. (html, ltex, rtf, mn,... formátumbn) Csk jó kommentből lesz jó dokumentáció! Speciális kezdet /** Rövid leírás ponttl zárv * Komplex osztály. * Komplex viselkedést megvlósító osztály. Részletesebb leírás * Csk feldt megoldásához szükséges műveleteket definiáltuk. */ C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -37- C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -38- Milyen furcs kommentek! /2 Speciális kezdet /** Rövid leírás ponttl zárv * Komplex osztály. * Komplex viselkedést megvlósító osztály. * Csk feldt megoldásához szükséges műveleteket definiáltuk. */ Részletesebb leírás Milyen furcs kommentek! /3 Prméterek dokumentálás /** * Konstruktor null, egy és két prméterrel Speciális kezdet * @prm r - vlós rész (lpértelmezése 0) * @prm i - képzetes rész (lpértelmezése 0) Rövid leírás */ Komplex(double r = 0, double i = 0) :re(r), im(i) { opertor double() { return sqrt(re*re + im*im); ///< bszolút érték friend istrem& opertor>>(istrem& s, Komplex& k) ; ///< Komplex beolvsás friend ostrem& opertor<<(ostrem& s, const Komplex k); ///< Komplex kiírás C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -39- C++ progrmozási nyelv BME-IIT Sz.I. 2011.03.01. -40-7