OOPC++ - operatory1 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.
OOPC++ - operatory2 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ą. 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). b jest interpretowane jako (b) lub (a, b) jest jednoargumentowym operatorem, a jest interpretowane jako () lub (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; }
OOPC++ - operatory3 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.
OOPC++ - operatory4 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
OOPC++ - operatory5 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; }
OOPC++ - operatory6 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 index val << endl; }
OOPC++ - operatory7 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; }
OOPC++ - operatory8 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; };
OOPC++ - operatory9 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; }
OOPC++ - operatory10 String::String(char* new_string) { character_array = strdup(new_string); string_length = strlen(character_array); }
OOPC++ - operatory11 Niebezpieczna czwórka Konstruktor bezargumentowy Konstruktor kopiujący Destruktor Operator przypisania