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 { Adatmezők int meret, *mut; Vektor(int meret); Vektor(int meret, int a); Konstruktorok, ~Vektor(); Destruktor int szamlal(int mit); }; 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); másoló konstruktor } tagfüggvény
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)