Treći deo razvoja klase za rad sa velikim brojevima. Ukoliko niste pročitali prethodna dva, počnite od prvog.
Dosta toga smo već iskodirali za našu klasu. Tačnije, obezbedili smo najbitnije, osnovne funkcionalnosti. Međutim, iz test primera se moglo primetiti da je ovakva klasa malo nezgodna za korišćenje.
a = a.saberi(b.podeli(c));
Zašto pisati ovako komplikovan kôd kad može jednostavnije:
a = a + b / c;
Ili čak:
a += b / c;
C++ nam dozvoljava da ovo uradimo uz pomoć preklapanja operatora (operator overloading), odnosno definisanja šta će koji operator da radi kada se susretne sa objektom naše klase. Neću da izmišljam toplu vodu objašnjavajući ovaj koncept, već ću vas samo uputiti na ovaj odličan tekst.
U C++u postoji nešto više od četrdeset operatora koji se mogu preklopiti, a mi ćemo iskoristiti samo one za koje već imamo napisane funkcije u klasi, pa će ovaj deo tutoriala zapravo biti veoma kratak. Počećemo sa još jednim proširenjem naše klase, pa posle nastavljamo sa operatorima za čitanje i ispisivanje brojeva.
VelikiBroj operator + (const VelikiBroj& desni) const; VelikiBroj operator - (const VelikiBroj& desni) const; VelikiBroj operator * (const VelikiBroj& desni) const; VelikiBroj operator / (const VelikiBroj& desni) const; VelikiBroj operator += (const VelikiBroj& desni); VelikiBroj operator -= (const VelikiBroj& desni); VelikiBroj operator *= (const VelikiBroj& desni); VelikiBroj operator /= (const VelikiBroj& desni); bool operator == (const VelikiBroj& desni) const; bool operator != (const VelikiBroj& desni) const; bool operator < (const VelikiBroj& desni) const; bool operator <= (const VelikiBroj& desni) const; bool operator > (const VelikiBroj& desni) const; bool operator >= (const VelikiBroj& desni) const;
Svi ovi operatori su definisani tako da rade isključivo sa objektima naše klase VelikiBroj. Naravno, bilo bi pametno obezbediti i sabiranje običnih integera sa velikim brojevima, ali to prepuštam vama – ovo ne bi trebalo da predstavlja problem, s obzirom da su sve potrebne funkcije već implementirane.
Stream operatori
Dakle, prvo želimo da omogućimo programeru lakše učitavanje i ispisivanje velikih brojeva.
ostream& operator << (ostream& o, const VelikiBroj& x) { o << x.uString(); return o; } istream& operator >> (istream& i, VelikiBroj& x) { string s; i >> s; x.izStringa(s); return i; }
Ova dva operatora za rad sa tokovima se uglavnom uvek implementiraju na isti način, pošto je njihova funkcija zapravo samo pretvaranje objekta u string, odnosno učitavanje objekta iz stringa.
Aritmetički operatori
Dalje, dodajemo +, -, * i /. Princip je isti za sva četiri operatora, pa prilažem kôd samo za sabiranje i deljenje.
VelikiBroj VelikiBroj::operator + (const VelikiBroj& desni) const { return this->saberi(desni); } VelikiBroj VelikiBroj::operator / (const VelikiBroj& desni) const { return this->podeli(desni); }
Relacioni operatori
Dodavanje relacionih operatora (za poređenja brojeva) zahteva samo pametno korišćenje funkcije koju već imamo.
bool VelikiBroj::operator == (const VelikiBroj& desni) const { return (this->uporedi(desni) == 0); } bool VelikiBroj::operator < (const VelikiBroj& desni) const { return (this->uporedi(desni) < 0); } bool VelikiBroj::operator <= (const VelikiBroj& desni) const { return (this->uporedi(desni) <= 0);
Operatori dodele
U ove operatore spada operator =, ali možemo posmatrati i operatore +=, -=, *= i /=. Operator dodele = ima predefinisano ponašanje za sve klase koje “kopira” sadržaj jedne klase u drugu. To čini tako što svakoj promenljivoj odredišnog objekta dodeli vrednost promenljive izvornog objekta uz pomoć operatora = za taj tip promenljive.
Ovo funkcioniše ukoliko klasa ne sadrži pokazivače, pa se svi podaci pravilno kopiraju (što je kod nas slučaj), ali je u suprotnom potrebno preklopiti operator =, alocirati memoriju i kopirati sve podatke iz izvornog objekta. Mi ćemo preklopiti samo ove druge operatore dodele.
VelikiBroj VelikiBroj::operator += (const VelikiBroj& desni) { return ((*this) = (*this) + desni); } VelikiBroj VelikiBroj::operator -= (const VelikiBroj& desni) { return ((*this) = (*this) - desni); }
Testiranje
Po istom principu je potrebno napisati funkcije koje bi uključile obične integer brojeve – kako kod aritmetičkih operacija, tako i kod poređenja. Nakon što završim tutorial, malo ću se pozabaviti svim mogućnostima koje bi klasa mogla da ima, a ona će između ostalog sadržati i podršku za rad sa integerima.
A dotle, uživajte u lepoj main() funkciji. Sledeći tekst će se baviti optimizacijom do sada napisanog kôda.
Klasu možete skinuti odavde.