Wstęp do programowania Dariusz Wardecki, wyk. X
Na czym polega przeciążanie operatorów Zamiast podawaê nazwí metody, moøna jπ oznaczyê z pomocπ symbolu operatora. Wtedy liczba argumentów metody zaleøy od liczby argumentów operatora. class Wektor double x, y; void add(wektor w); ; void Wektor::add(Wektor w) x += w.x; y += w.y; Wektor w, v; w.add(v); class Wektor double x, y; void operator +=(Wektor w); ; void Wektor::operator +=(Wektor w) x += w.x; y += w.y; Wektor w, v; w += v; // wywo anie metody operator +=
Przeciążanie operatorów Argumenty funkcji wywo ywanej jako operator nie muszπ byê tego samego typu jak obiekt, w kontekúcie którego wywo ywana jest metoda. class Wektor double x, y; void operator *=(double r); ; void Wektor::operator *=(double r) x *= r; y *= r; Wektor w; w *= 2; // wywo anie metody operator *= class Wektor double x, y; void operator +=(double r); ; void Wektor::operator +=(double r) x += r; Wektor w; w += 1; // wywo anie metody operator +=
Przeciążanie operatorów Przykład: Napisz program, który wykorzystując przciażenie operatorów + oraz * definiuje kolejno operację doawania oporników połączonych szeregowo i równolegle.
Przeciążanie operatora [] Moøna takøe przeciπøaê operator wskazania elementu tablicy []. Reprezentujπca go funkcja najczíúciej zwraca referencjí, aby moøna by o uøyê jej po lewej stronie operator przypisania =. class Wektor double x, y; double& wsp(int n) return n == 1? x : y; ; Wektor w; class Wektor double x, y; double& operator [](int n) return n == 1? x : y; ; Wektor w; w.wsp(1) = 2; // wywo anie metody wsp() w[1] = 2; // wywo anie metody operator []
Konstruktor Jeúli w czasie tworzenia obiektu danej klasy naleøy wykonaê jakπú akcjí (np. zarezerwowaê pamiíê), to jednym z jej sk adników powinien byê konstruktor (ang. constructor). Konstruktor Metoda wywo ywana automatycznie (z odpowiednimi argumentami) podczas tworzenia obiektu. Zawsze ma takπ nazwí, jak klasa, której jest sk adnikiem. class Tablica double *elem; int n; double& operator [](int n); Tablica(int n_el); ; Tablica::Tablica(int n_el) elem = new double[n_el]; if (elem) n = n_el; Tablica tab(10); // wywo anie konstruktora
Definiowanie wielu konstruktorów Wjednejklasiemoøe byê wiele konstruktorów, ale muszπ one róøniê sií jednoznacznie liczbπ lub typami danych argumentów. class Tablica double *elem; int n; double& operator [](int n); void init(int n_el); Tablica(int n_el); Tablica(int n_el, double r); ; void Tablica::init(int n_el) elem = new double[n_el]; if (elem) n = n_el; Tablica::Tablica(int n_el) init(n_el); Tablica::Tablica(int n_el, double r) init(n_el); for (int i = 0; i < n; i++) elem[i] = r; Tablica tab(10); Tablica tmp(10, -1); // Tablica(int) // Tablica(int, double)
Lista inicjalizacyjna class Matrix22 double w1k1, w1k2, w2k1, w2k2; Matrix22(void): w1k1(0), w1k2(0), w2k1(0), w2k2(0) Matrix22(double r): w1k1(r), w1k2(0), w2k1(0), w2k2(r) Matrix22(double a, double b, double c, double d): w1k1(a), w1k2(b), w2k1(c), w2k2(d) double det(void) const return w1k1*w2k2 - w1k2*w2k1; Matrix22 operator +(Mattix22 m) return Matrix22(w1k1 + m.w1k1, w1k2 + m.w1k2, w2k1 + m.w2k1, w2k2 + m.w2k2); ; int main() Matrix22 A(1), B(2), C; C = A + B; cout << C.w1k1 << " " << C.w1k2 << " " << C.w2k1 << " " << C.w2k2 << endl; A = C + B; cout << A.w1k1 << " " << A.w1k2 << " " << A.w2k1 << " " << A.w2k2 << endl; B = A + C; cout << B.w1k1 << " " << B.w1k2 << " " << B.w2k1 << " " << B.w2k2 << endl; return 0;
Kiedy wywoływane są konstruktory Dla zmiennych lokalnych Bezpoúrednio po utworzeniu zmiennej w czasie wykonywania bloku zawierajπcego jej definicjí (przewaønie w miejscu odpowiadajπcym po oøeniu definicji zmiennej w obríbie bloku). Dla zmiennych dynamicznych Bezpoúrednio po utworzeniu zmiennej z uøyciem new, np.: wsk = new Tablica(10); Dla zmiennych globalnych lub statycznych Przed rozpoczíciem wykonywania funkcji main(), bezpoúrednio po zarezerwowaniu pamiíci na te zmienne.
Destruktor Jeøeli przed usuniíciem obiektu z pamiíci trzeba przeprowadziê jakπú dodatkowπ czynnoúê (np. zwolniê pamiíê zarezerwowanπ przez konstruktor), to jednym ze sk adników klasy powinien byê destruktor (ang. destructor). Destruktor Metoda wykonywana automatycznie bezpoúrednio przed usuniíciem obiektu z pamiíci. Jej nazwa musi sk adaê sií ze znaku ~ inazwyklasy, której jest sk adnikiem. Do destruktora nie moøna przekazywaê argumentów, wiíc w kaødej klasie moøe byê co najwyøej jeden destruktor.
Definiowanie destruktora class Tablica double *elem; int n; double& operator [](int n) return elem[n]; void init(int n_el); Tablica(int n_el) init(n_el); Tablica(int n_el, double r); ~Tablica(void); ; void Tablica::init(int n_el) elem = new double[n_el]; if (elem) n = n_el; Tablica::Tablica(int n_el, double r) init(n_el); for (int i = 0; i < n; i++) elem[i] = r; Tablica::~Tablica(void) n = 0; if (elem) delete [] elem; Tablica *wsk; wsk = new Tablica(10, 0); delete wsk; // ~Tablica()
Kiedy wywoływany jest destruktor? Dla zmiennych lokalnych Bezpoúrednio przed usuniíciem zmiennej z pamiíci po zakoòczeniu wykonywania bloku zawierajπcego jej definicjí (przewaønie w miejscu odpowiadajπcym po oøeniu klamry koòczπcej blok). Dla zmiennych dynamicznych Bezpoúrednio przed usuniíciem zmiennej z uøyciem delete. Dla zmiennych globalnych lub statycznych Po zakoòczeniu wykonywania funkcji main(), bezpoúrednio przed zwolnieniem pamiíci zajmowanej przez te zmienne.
Składniki klasy dostępne tylko dla metod CzÍsto wygodnie jest zadeklarowaê sk adnik klasy jako dostípny tylko dla metod bídπcych jej sk adnikami. W tym celu trzeba poprzedziê jego definicjí modyfikatorem dostípu private. class Tablica private: double *elem; int n; double& operator [](int n); void init(int n_el); Tablica(int n_el); Tablica(int n_el, double r); ~Tablica(void); ; void Tablica::init(int n_el) elem = new double[n_el]; // OK if (elem) // OK n = n_el; // OK Tablica tab(10); cout << tab.n << endl; // B πd!
Czytanie oraz zapis do pliku w C++ Pliki tekstowe (Aąbf#$123&) Pliki binarne (10011011010110110)
Definiowanie strumienia obsługa struminia program-konsola (ekran, klawiatura) klasa <iostream> cout cin obsługa strumienia program-dysk (plik) klasa <fstream> ofstream plik; ifstream plik; uwagi obiekt cout predefiniowany obiekt cin predefiniowany
Pobieranie danych ze strumienia operator lub funkcja >> get(char* gdzie, int ile, char ogran = \n ) Uwagi Operator >> domyślnie pomija białe znaki. Wczytuje ciąg znaków do pojawiania się kolejnego białego znaku Ogranicznik nie jest wyjmowany ze strumienia getline(char* gdzie, int ile, char ogran = \n ) Ogranicznik jest wyjmowany ze strumienia read(char* gdzie, int ile) Nie dopisuje na koncu stringu znaku NULL
Pliki tekstowe - odczyt #include<iostream> #include<fstream> Dodajemy klasę fstream using namespace std; int main(int argc, char *argv[])!! char *buff = new char;! ifstream plik;! plik.open("dane.txt");! plik.getline(buff, 99);! cout << ++buff << endl;! plik.getline(buff, 99);! cout << buff << endl;!! plik.close();! return 0; Definiujemy bufor na dane Definiujemy i otwieramy strumień Wczytujemy dane ze strumienia do bufora Zamykamy strumień
Zapisywanie danych do strumienia operator lub funkcja Uwagi << przekierowanie do strmienia put(char znak) Wstawia do strumienia jeden znak write(char* skąd, int ile) Wstawia do strumienia określoną ilość danych