Bevezetés a programozásba II 5. Előadás: Másoló konstruktor, túlterhelés, operátorok
Emlékeztető struct Vektor { int meret, *mut; Vektor(int meret); int szamlal(int mit); }; int Vektor::szamlal(int mit) { int c=0; for (int i=0;i<meret;i++) if(mut[i]==mit) c++; return c; } int main() { Vektor v(5); v.szamlal(0);.. felület (interface) Típus megvalósítás (implementáció)
Emlékeztető struct Vektor { int meret, *mut; Vektor(int meret); Vektor(int meret, int a); ~Vektor(); int szamlal(int mit); }; Adatmezők Konstruktorok, Destruktor Tagfüggvények
Másoló konstruktor Kezdőérték int a=4; int b(a); vagy int b=a; Vektor a(5);.. Vektor b(a); Megtehető, de váratlan hatás jelentkezik a: 5 mut
Másoló konstruktor Kezdőérték int a=4; int b(a); vagy int b=a; Vektor a(5);.. Vektor b(a); Megtehető, de váratlan hatás jelentkezik a: 5 mut b: 5 mut
Másoló konstruktor a: 5 mut b: 5 mut a[3] = 42; cout << b[3]; // 42! ez nem biztonságos másolat!
Másoló konstruktor Megoldás: a Vektor tartalmazzon Vektor paraméterű konstruktort! Vektor(Vektor & masik); Vektor::Vektor(const Vektor & masik) { meret=masik.meret; mut = new int[meret]; for (int i=0;i<meret;i++) mut[i]=masik.mut[i]; }
Másoló konstruktor a: 5 mut b: 5 mut Vektor::Vektor(const Vektor & masik) { meret=masik.meret; mut = new int[meret]; for (int i=0;i<meret;i++) mut[i]=masik.mut[i]; }
Összefoglalás Ha tartalmaz referenciát egy rekord, felmerül a másolás biztonsága Shallow copy deep copy A másoló konstruktor (copy constructor) egy speciális konstruktor, aminek egy darab paramétere van, a lemásolandó szerkezet. Mindig létezik alapértelmezett másoló konstruktor Kifejezések kiértékelése : a=b+c+d; Érték szerinti paraméter átadás
Túlterhelés Ugyanazon a néven több függvény, amik paraméterlistájukban térnek el Egyértelműség Paraméterek típusa vagy száma alapján Visszatérési érték nem különböztet meg Komoly kuszálási lehetőség : lehetőleg ugyanahhoz függvénynévhez hasonló műveleteket társítsunk!
Túlterhelés string beolvas(istream &); string beolvas(string fajlnev); string beolvas(string fajlnev, int index); string beolvas(istream &, char terminalojel); Vigyázzunk az alapértelmezett paraméterértékkel: string beolvas(string fajlnev); string beolvas(string fajlnev, int index=0); hibás!
Túlterhelés : feloldás Néhány típus egymásba automatikusan átalakítható, ami bonyolít a helyzeten: Ha nincs szükség konverzióra Ha szükség van konverzióra, de az automatikus átalakításokkal csak egy lehetőség érhető el Ha szükség van konverzióra, automatikussal nem, de saját konverziókkal csak egy lehetőség érhető el Formális nyelvek, nyelvi elemző
Összefoglalás Túlterhelünk függvényeket, ha hasonló műveletet különböző típusokkal kell végrehajtani Túl sok, vagy túl kevés túlterhelés váratlan függvényhívásokat eredményezhet a nehezen végiggondolható túlterhelés-feloldás miatt Ilyenek például az operátorok is
Operátorok Első közelítés: az operátorok függvények, metódusok Vektor a,b; c=a+b; Vektor operator + (Vektor a, const Vektor& b) { return a.hozzaad(b); } tagfüggvény másoló konstruktor
Operátorok függvények Operátoroknak véges listája használható Az operátor csak adott számú paraméterrel rendelkezhet, attól függően, hogy önállóan, vagy metódusként használjuk A függvények csak zárójeles formában használhatóak (prefix vs infix forma) Operátornál nincs alapértelmezett paraméterérték
Operátorok függvényként: S& operator+(s& a, S& b) { } metódusként: S& S::operator+(S& a) { } Szükségesek az adatmezők? Mindkettő szerepelhet, ilyenkor a túlterhelés szabályai érvényesek Egy operandusú (referencia, negatív előjel, konverzió) is lehet
Operátorok : értékadás T& T::operator=(T& masik) nem összetévesztendő a másoló konstruktorral Változó definiálása NEM ez az eset: T a=b; a másoló konstruktort hívja meg Referencia visszatérési típus az a=b=c érdekében Vektor& Vektor::operator=(Vektor &masik){ if (mut)delete mut; meret=masik.meret; mut=new int[meret]; for(int i=0;i<meret;i++) mut[i]=masik.mut[i]; }
Operátorok : egyenlőségvizsgálat bool T::operator==(T& masik) bool Vektor::operator==(Vektor &masik){ if (meret==masik.meret) { for(int i=0;i<meret;i++) { if (mut[i]!=masik.mut[i]) return false; return true; } } else return false; }
Operátorok : kiírás ostream& T::operator<< (ostream& out) Referencia a cout << a << b érdekében: cout << a << b zárójelezve (cout << a) << b ostream& Vektor::operator<<(ostream &out) { out << "[ "; for(int i=0;i<meret;i++) out << mut[i] << " "; out << "]" << endl; return out; }
Operátorok : konverzió T::operator T2() { } T2 típusra konvertálásra ad lehetőséget struct racionalis { int szamlalo, nevezo; operator double() { return double(szamlalo)/nevezo; } Óvatosság
Operátorok : kifejezések A kifejezések kiértékelése a túlterhelt operátorok szerint keresett egyértelmű zárójelezés Szintaxisfa S a,b,c; a=a+-b+c; a=a+-b+c
Operátorok : kifejezések A kifejezések kiértékelése a túlterhelt operátorok szerint keresett egyértelmű zárójelezés Szintaxisfa S a,b,c; a=a+-b+c; a = a+-b+c
Operátorok : kifejezések A kifejezések kiértékelése a túlterhelt operátorok szerint keresett egyértelmű zárójelezés Szintaxisfa S a,b,c; a=a+-b+c; = a + a -b+c
Operátorok : kifejezések A kifejezések kiértékelése a túlterhelt operátorok szerint keresett egyértelmű zárójelezés Szintaxisfa S a,b,c; a=a+-b+c; = a + a + -b c
Operátorok : kifejezések A kifejezések kiértékelése a túlterhelt operátorok szerint keresett egyértelmű zárójelezés Szintaxisfa S a,b,c; a=a+-b+c; = a + a + - c b
Összefoglalás Hatékony eszköz Tömör kód Rugalmasság Majdnem minden operátor túlterhelhető kivételek: sizeof? : ::. (.*, typeid)