110 likes | 314 Views
Operatory. class complex { private: double re, im; public: complex (double r, double i = 0) { re = r; im = i; } friend complex operator+ (complex, complex); friend complex operator*(complex, complex); complex& operator += (complex); }; void f() { complex a = complex (1.3, 4);
E N D
Operatory • class complex { • private: • double re, im; • public: • complex (double r, double i = 0) { re = r; im = i; } • friend complex operator+ (complex, complex); • friend complex operator*(complex, complex); • complex& operator += (complex); • }; • void f() • { • complex a = complex (1.3, 4); • complex b = complex(3); • complex c(0); • c = b + a; • c = b+c * a; • c = b + 10; // poprawne - nastąpi niejawna konwersja • } • Można definiować operatory dla: • + - * / % & | ! itd. • = < > += itd. • << >> && || ++ -- itd. • [ ] ( ) new delete • Nie można zmienić arności ani priorytetów operatorów. • Operatory są z definicji przeciążone.
Zasada: • operator musi mieć co najmniej 1 argument będący • obiektem klasy (nie dotyczy new i delete). • Zwykle operator jest albo funkcją składową jakiejś • klasy, albo jej funkcją zaprzyjaźnioną. • Niech @ będzie dwuargumentowym operatorem. Musi być albo • jednoargumentową funkcją składową (niejawnym pierwszym • argumentem jest obiekt, w którym wykonywana jest metoda), • albo dwuargumentową funkcją zaprzyjaźnioną (pierwszy argument • jest jawny). • a @ b jest interpretowane jako a.operator@ (b) • lub operator@ (a, b) • Jeśli @ jest jednoargumentowym operatorem, • to @ a jest interpretowane jako a.operator@ () • lub operator@ (a) • complex operator+ (complex a, complex b) • { • return complex (a.re + b.re, a.im + b.im); • } • // i analogicznie operator* • inline complex& complex::operator+= (complex a) • { • re += a.re; • im += a.im; • return *this; • }
Przeciążenie operatora << • class ostream { • // .... • public: • ostream& operator<< (char*); • ostream& operator<< (int i); • // ... • }; • Możemy przeciążyć ten operator. Na przykład: • class complex { • private: • double re, im; • public: • // .... • friend ostream& operator<< (ostream& os, complex& c); • }; • ostream& operator<< (ostream& os, complex& c) • { • os << “(“ << c.re << “,“ << c.im << “)”; • return os; • } • Można teraz napisać: • complex c = complex (3.5, 6.7); • cout << c; • Uwaga: operator << nie może być metodą klasy complex, ponieważ • jego pierwszym argumentem ma być strumień, a nie • obiekt complex.
Przeciążanie operatora [ ] • Wyrażenie x [ i ] jest interpretowane jako x . operator [ ] ( i ). • Operator [ ] musi być funkcją składową. • Przykład: dynamiczna tablica indeksowana napisami, służąca do • zliczania słów z pliku (coś w rodzaju słownika, o kluczach będących • napisami i wartościach będących liczbami). • struct pair { • char *index; • int val; • }; • class assoc_array { • private: • ::pair *vec; // tablica par, :: bo w std też jest pair • int max, free; // free - pierwsze wolne miejsce • public: • assoc_array (int); // konstruktor • int& operator [ ] (char *); // ma dać drugi element pary • void print_all ( ); • }; • assoc_array :: assoc_array (int s) • { • max = (s > 16) ? s : 16; • free = 0; • vec = new ::pair[max]; • } • Przykład użycia: • char buf [MAX]; • assoc_array table (512); • while (cin >> word) • table [word] +; // table[word] jest referencją do val
int& assoc_array :: operator [ ] (char *s) • // Szuka pary o kluczu p; jeśli nie ma, to tworzy. Zwraca referencję do • // wartości (drugiego elementu pary) • { • ::pair *pp; • for (pp = &vec [free-1]; vec <= pp; pp--) • if (strcmp (s, pp -> index) == 0) return (pp -> val); • if (free == max ) // przepełnienie • { • ::pair* nvec = new ::pair [max * 2]; • for (int i = 0; i < max; i++) • nvec [ i ] = vec [ i ]; • delete[] vec; • vec = nvec; • max = 2 * max; • } • pp = &vec [free ++]; • pp -> index = new char [strlen (s) + 1]; • strcpy ( pp -> index, s); • pp -> val = 0; • return (pp -> val); • } • void assoc_array :: print_all () • { • for (int i = 0; i < free; i++) • cout << endl << vec [i].index << “: “ << vec [i].val; • }
Przeciążanie operatora () • Jest to przeciążenie wywoływania funkcji, czyli wyrażenia postaci • wyr (lista_wyr) • gdzie wyr jest pierwszym argumentem operatora (), a lista_wyr drugim. • Przykład - iterator dla assoc_array. • Do deklaracji klasy assoc_array dodajemy • friend class iterator_assoc; • class iterator_assoc { • private: • const assoc_array& tab; // iterowana tablica • int i; // bieżący indeks • public: • iterator_assoc (const assoc_array& s) : tab(s) { i = 0; } • ::pair* operator () () // operator () • { return (i < tab.free) ? &tab.vec[i++] : 0; } • }; • main () // program liczy liczbę wystąpień słów na wejściu • { • const MAX = 256; • char buf [MAX]; • assoc_array liczniki (512); • while (cin >> buf) liczniki [buf]++; • iterator_assoc nast (liczniki); // inicjalizacja iteratora • ::pair * p; • while (p = nast () ) • cout << p -> index << “: “ << p -> val << endl; • }
Konwersje typów - operatory konwersji • X :: operator T () definiuje konwersję z X do T • class String { • public: • ..... • operator char* () { return tablica; } • private: • char* tablica; int dlugosc; • }; • String s = ...; • char *p = s; // konwersja z typu String do char* • Przeciążanie operatora = • Problem ten sam, co z konstruktorem kopiującym. • class Napis • { • private: • char *ptr; size_t len; • public: • Napis () { ptr = NULL; len = 0; } • // konstruktor kopiujący: • Napis (const Napis& n ) {ptr = strdup(n.ptr); len = strlen(ptr);} • Napis& operator= (const Napis& n); • virtual ~Napis () { /*if (ptr != NULL)*/ delete ptr; } • }; • Napis& Napis :: operator= (const Napis& n) • { if (this != &n) • { delete ptr; • ptr = new char [len = n.len]; • strcpy (ptr, n.ptr); • } • return *this; • }
class String { • public: • // Konstruktory/Destruktory • String() • {character_array = new char[1]; character_array[0] = '\0';} • String(char* new_string); • String(String& new_string); // konstruktor kopiujący • String(int integer_to_convert); • String(float float_to_convert); • ~String() { } • // Funkcje implementujące operacje • size_t size() {return string_length;} • String& copy(); • int as_integer(); • float as_float(); • String& read_up_to (char delimiter); • String& break_at (char delimiter); • bool contains_string (char* a_character_array); • int locate_string (char* a_character_array); • String& copy_sequence (int sequence_start, int sequence_end); • // Operatory • String& operator+ (String& a_string); • String& operator+= (String& a_string); • String& operator= (String& a_string); • String& operator= (const char* a_character_array); • int operator< (String& a_string); • int operator> (String& a_string); • int operator== (String& a_string); • operator char* () {return character_array; } // konwersja • friend ostream& operator<< (ostream& os, String& a_string); • private: • char* character_array; • size_t string_length; • };
String& String::operator+ (String& a_string) { size_t total_size = string_length + strlen(a_string) + 1; char* temp_array = new char[total_size]; char* char_array = a_string; strcpy(temp_array, character_array); strcat(temp_array, char_array); String* new_string = new String(temp_array); delete temp_array; return *new_string; } String& String::operator= (String& a_string) { char* new_char_array = a_string; delete character_array; character_array = new char[strlen(new_char_array) + 1]; strcpy(character_array, new_char_array); string_length = strlen(character_array); return *this; } String& String::operator= (const char* a_character_array) { delete character_array; character_array = new char[strlen(a_character_array) + 1]; strcpy(character_array, a_character_array); string_length = strlen(character_array); return *this; } int String::operator==(String& a_string) { return(strcmp(character_array, (char*) a_string) == 0); } ostream& operator<< (ostream& os, String& a_string) { os << a_string.character_array; return os; }
String::String(char* new_string) { character_array = strdup(new_string); string_length = strlen(character_array); }
Niebezpieczna czwórka • Konstruktor bezargumentowy • Konstruktor kopiujący • Destruktor • Operator przypisania