Projektowanie i programowanie obiektowe (materiały do wykładu cz. VII) Jacek Cichosz www.zssk.pwr.wroc.pl Katedra Systemów i Sieci Komputerowych Politechnika Wrocławska
Dziedziczenie 265 Klasy abstrakcyjne class Figura{ public: // Czyste funkcje wirtualne virtual void rysuj() const = 0; virtual void przesun( int, int ) = 0; ; Klasa abstrakcyjna reprezentuje abstrakcyjne pojęcie i ma sens tylko jako klasa podstawowa dla jakiejś klasy pochodnej.
Dziedziczenie 265 Klasy abstrakcyjne class Figura{ public: // Czyste funkcje wirtualne virtual void rysuj() const = 0; virtual void przesun( int, int ) = 0; ; Klasa abstrakcyjna reprezentuje abstrakcyjne pojęcie i ma sens tylko jako klasa podstawowa dla jakiejś klasy pochodnej. Klasa abstrakcyjna to taka klasa, która zawiera przynajmniej jedną czystą funkcję wirtualną.
Dziedziczenie 265 Klasy abstrakcyjne class Figura{ public: // Czyste funkcje wirtualne virtual void rysuj() const = 0; virtual void przesun( int, int ) = 0; ; Klasa abstrakcyjna reprezentuje abstrakcyjne pojęcie i ma sens tylko jako klasa podstawowa dla jakiejś klasy pochodnej. Klasa abstrakcyjna to taka klasa, która zawiera przynajmniej jedną czystą funkcję wirtualną. Nie można tworzyć żadnych obiektów takiej klasy.
Dziedziczenie 266 Czyste funkcje wirtualne Czyste funkcje wirtualne różnią się od zwykłych funkcji wirtualnych inicjatorem 0, np. class Figura{ public: virtual void rysuj() const = 0; ; Sensownej definicji funkcji wirtualnej zdeklarowanej jako czysta, można dostarczyć dopiero w klasach pochodnych. Czysta funkcja wirtualna, której nie zdefiniowano w klasie pochodnej pozostaje czystą funkcją wirtualną, a klasa pozostaje abstrakcyjna i nie można tworzyć żadnych jej obiektów.
Dziedziczenie 267 Czyste funkcje wirtualne class Figura{ public: virtual void rysuj() const = 0; virtual void przesun( int, int ) = 0; ; class Okrag : public Figura{ Punkt srodek; int promien; public: Okrag( Punkt, int ); void rysuj() const; void przesun( int, int ); ; Klasy abstrakcyjnej można użyć jedynie jako klasy podstawowej dla innej klasy.
Dziedziczenie 268 Definiowanie funkcji wirtualnych etapami Czysta funkcja wirtualna, której nie zdefiniowano w klasie pochodnej pozostaje czystą funkcją wirtualną, a klasa pochodna pozostaje. Funkcje wirtualne można definiować etapami w kolejnych klasach pochodnych. class A{ public: virtual void f() = 0; virtual void g() = 0; ; A a; // Błąd! nie można tworzyć obiektu klasy A class B : public A{ public: void f(); // Unieważnia A :: f() ; B b; // Błąd! B jest klasą abstrakcyjną class C : public B{ public: void g(); // Unieważnia A :: g() ; C c; // O.K.
Dziedziczenie 269 Biblioteka figur założenia Klasa abstrakcyjna Figura definiuje ogólne pojęcie figury dwuwymiarowej poprzez zbiór operacji jakie można na niej wykonać.
Dziedziczenie 269 Biblioteka figur założenia Klasa abstrakcyjna Figura definiuje ogólne pojęcie figury dwuwymiarowej poprzez zbiór operacji jakie można na niej wykonać. Konkretne figury: Okrag, Linia, Prostokat,... klasy potomne klasy Figura.
Dziedziczenie 269 Biblioteka figur założenia Klasa abstrakcyjna Figura definiuje ogólne pojęcie figury dwuwymiarowej poprzez zbiór operacji jakie można na niej wykonać. Konkretne figury: Okrag, Linia, Prostokat,... klasy potomne klasy Figura. Każda określona figura definiuje dla siebie reprezentację, sposób rysowania i przesuwania.
Dziedziczenie 269 Biblioteka figur założenia Klasa abstrakcyjna Figura definiuje ogólne pojęcie figury dwuwymiarowej poprzez zbiór operacji jakie można na niej wykonać. Konkretne figury: Okrag, Linia, Prostokat,... klasy potomne klasy Figura. Każda określona figura definiuje dla siebie reprezentację, sposób rysowania i przesuwania. Operacje dla każdej figury powinny być dostępne wyłączne przez interfejs dostarczany przez klasę Figura.
Dziedziczenie 269 Biblioteka figur założenia Klasa abstrakcyjna Figura definiuje ogólne pojęcie figury dwuwymiarowej poprzez zbiór operacji jakie można na niej wykonać. Konkretne figury: Okrag, Linia, Prostokat,... klasy potomne klasy Figura. Każda określona figura definiuje dla siebie reprezentację, sposób rysowania i przesuwania. Operacje dla każdej figury powinny być dostępne wyłączne przez interfejs dostarczany przez klasę Figura. Chcemy przydzielać pamięć dla obiektów figur wymaganie wirtualnego destruktora.
Dziedziczenie 270 Graficzne współrzędne ekranowe punktu struct Punkt{ short x, y; void operator += ( Punkt d ){ x += d.x; y += d.y; inline Punkt( int l, int r ) : x( l ), y( r ) { ; (0,0) y getmaxy() x (x,y) getmaxx() Funkcja void Punkt :: operator += ( Punkt d ) służy do wyznaczania współrzędnych punktu po jego przesunięciu o wektor d. Klasa Punkt w pewnych sytuacjach oznacza współrzędne punktu, np. w reprezentacji różnych figur, a w innych oznacza współrzędne wektora d = [x, y], np. w argumencie funkcji operator += ().
Dziedziczenie 271 Klasa podstawowa class Figura{ public: virtual void rysuj() const = 0; virtual void przesun( Punkt ) = 0; virtual ~Figura() = 0; ; Figura :: ~Figura(){ Rysowanie polega na wywołaniu odpowiedniej funkcji bibliotecznej. Przesuwanie o zadany wektor polega na obliczeniu nowych współrzędnych figury.
Dziedziczenie 272 Reprezentacja prostokąta class Prostokat : public Figura{ Punkt lg, pd; public: inline Prostokat( Punkt l, Punkt r ) :lg( l ), pd( r ) { void rysuj() const; void przesun( Punkt ); ~Prostokat(); ; // Rysowanie za pomocą funkcji bibliotecznej void Prostokat :: rysuj() const{ rectangle( lg.x, lg.y, pd.x, pd.y ); Prostokat :: ~Prostokat(){ //... Usuń rysunek figury z ekranu
Dziedziczenie 273 Przesunięcie prostokąta na płaszczyźnie // Wyznacz nowe położenie figury void Prostokat :: przesun( Punkt p ){ lg += p; pd += p;
Dziedziczenie 274 Reprezentacja odcinka linii class Linia : public Figura{ Punkt pocz, kon; public: inline Linia( Punkt l, Punkt r ); void rysuj() const; void przesun( Punkt ); ~Linia(); ; Linia :: Linia( Punkt l, Punkt r ) : pocz( l ), kon( r ){ void Linia :: rysuj() const{ line( pocz.x, pocz.y, kon.x, kon.y ); Linia :: ~Linia(){ // Usuń rysunek odcinka z ekranu
Dziedziczenie 275 Przesunięcie linii na płaszczyźnie // Wyznacz nowe polożenie odcinka na ekranie void Linia :: przesun(punkt p){ pocz += p; kon += p;
Dziedziczenie 276 Reprezentacja okręgu class Okrag : public Figura{ Punkt srodek; short promien; public: Okrag( Punkt s, int r ); void rysuj() const; void przesun( Punkt ); ~Okrag(); ; Okrag :: Okrag( Punkt s, int r ) : srodek(s), promien( r ){ void Okrag :: rysuj() const{ circle( srodek.x, srodek.y, promien ); Okrag :: ~Okrag(){ // Usuń rysunek okręgu z ekranu
Dziedziczenie 277 Przesunięcie okręgu na płaszczyźnie // // Wyznacz nowe położenie środka // void Okrag :: przesun( Punkt p ){ srodek += p;
Dziedziczenie 278 Program użytkowy void main(){ int driver = DETECT, mode; initgraph( &driver, &mode, "c:\\borlandc\\bgi"); if(graphresult()!= grok ){ cprintf("blad grafiki\n"); exit(1); Figura * p[] = { new Okrag( Punkt( 100, 60 ), 40 ), new Prostokat( Punkt(200, 200), Punkt(340, 400 )), new Linia( Punkt(0,0), Punkt(200, 300)); rysuj_tab(p,sizeof(p)/sizeof(p[0])); p[1]->przesun(punkt(100, 100)); for( int i = 0; i < sizeof(p)/sizeof(p[0]) ; i++ ) delete p[i]; closegraph(); void rysuj_tab( Figura * p[], int rozmiar ){ for( int i = 0; i < rozmiar ; i++ ) p[i]->rysuj();
Dziedziczenie 279 Reprezentacja ogólnego pojęcia class Koszyk{ protected: int licznik; // Licznik elementów public: int ilosc() const { return licznik; Koszyk() : licznik( 0 ) { virtual ~Koszyk() = 0; virtual int dodaj( RecordT * ) = 0; virtual int usun( RecordT * ) = 0; virtual void usun_wszystko() = 0; ; Koszyk :: ~Koszyk() {
Dziedziczenie 280 Reprezentacja pojęcia Koszyk za pomocą listy // Koszyk zrealizowany za pomocą listy class KoszykLista : public Koszyk{ // Dane potrzebne do reprezentacji listy public: KoszykLista(); // Zwolnij pamięc elementów listy ~KoszykLista(); int dodaj( RecordT * ); int usun( RecordT * ); void usun_wszystko(); ;
Dziedziczenie 281 Koszyk oparty na tablicy // Koszyk zrealizowany za pomocą tablicy class KoszykTab : public Koszyk{ // Dane potrzebne do reprezentacji tablicy public: // Utwórz tablicę o zadanym rozmiarze KoszykTab( int ); // Zwolnij pamięć elementów tablicy virtual ~KoszykTab(); virtual int dodaj( RecordT * ); virtual int usun( RecordT * ); void usun_wszystko(); ;
Dziedziczenie 282 Koszyk oparty tablicy posortowanej // Koszyk zrealizowany za pomocą uporządkowanej tablicy class KoszykSrt : public KoszykTab{ public: // Utwórz tablicę o zadanym rozmiarze KoszykSrt( int r ) : KoszykTab( r ); // Destruktor nie robi nic // Pamięć zwalnia destruktor klasy KoszykTab ~KoszykSrt() { int dodaj( RecordT * ); int usun( RecordT * ); ;
Dziedziczenie 283 Wypelnianie koszyka void robimy_zakupy( Koszyk & k ){ RecordT * rp; while( (rp = czekaj_na_wybor_klienta())!= NULL ) k.dodaj( rp ); KoszykLista list; robimy_zakupy( list ); KoszykSrt srt; robimy_zakupy( srt );
Dziedziczenie 284 Ogólna klasa do przeglądania zawartości koszyka class KoszykItr{ public: // Inicjuj przeglądanie koszyka virtual void na_poczatek() = 0; virtual void na_koniec() = 0; // Zwróć wskaźnik bieżącego elementu virtual RecordT * biezacy() = 0; virtual RecordT * nastepny() = 0; virtual RecordT * poprzedni() = 0; ;
Dziedziczenie 285 Przeglądanie zawartości koszyka listowego class KoszykListaItr : public KoszykItr{ public: KoszykListaItr( KoszykLista & ); // Inicjuj przeglądanie koszyka void na_poczatek(); void na_koniec(); // Zwróć wskaźnik bieżącego elementu RecordT * biezacy(); RecordT * nastepny(); RecordT * poprzedni(); ;
Dziedziczenie 286 Przeglądanie zawartości koszyka tablicowego class KoszykTabItr : public KoszykItr{ public: KoszykTabItr( KoszykTab & ); // Inicjuj przeglądanie koszyka void na_poczatek(); void na_koniec(); // Zwróć wskaźnik bieżącego elementu RecordT * biezacy(); RecordT * nastepny(); RecordT * poprzedni(); ;
Dziedziczenie 287 Drukowanie zawartości koszyka void drukuj_koszyk( KoszykItr & itr ){ drukuj_naglowek(); // Np. Oto twoje zakupy: RecordT * rp; while( ( rp = nastepny() )!= NULL ) drukuj_rekord( rp ); KoszykTab tab( 20 ); KoszykSrt srt( 50 ); KoszykLista list; drukuj_koszyk(koszyktabitr( tab )); drukuj_koszyk(koszyksrtitr( srt )); drukuj_koszyk(koszyklistaitr( list ));
Dziedziczenie 288 Klasy strumieniowe ios fstreambase istream ostream strstreambase ifstream istrstream ofstream iostream ostrstream fstream strstream
Dziedziczenie 289 Zakres odpowiedzialności klas strumieniowych Klasa C ios istream ostream iostream fstreambase ifstream ofstream fstream strstreambase istrstream ostrstream strstream Zakres odpowiedzialności Sterowanie formatem, stan strumienia Operacje wejściowe Operacje wyjściowe Operacje wejściowe i wyjściowe Klasa podstawowa do operacji we/wy na plikach Operacje wejściowe na plikach Operacje wyjściowe na plikach Operacje wejściowe i wyjściowe na plikach Klasa podstwowa do operacji we/wy na pamięci Operacje wejściowe na pamięci Operacje wyjściowe na pamięci Operacje wejściowe i wyjściowe na pamięci
Dziedziczenie 290 Stany strumienia Z każdym strumieniem jest związany jego stan. Zastosowanie: obsługa błędów i różnych warunków takich jak napotkanie końca strumienia. Funkcje do testowania stanu strumienia (klasa: ios). Funkcja bad() eof() fail() good() operator!() Opis Strumień jest zniszczony. Napotkano koniec strumienia. Następna operacja zakończy się niepowodzeniem. Następna operacja może się zakończyć sukcesem. Zwraca TRUE, jeśli strumień w stanie bad lub fail Zniszczony strumień oznacza, że znaki zostały zgubione.
Dziedziczenie 291 Testowanie stanu strumienia w warunku #include <iostream.h> void main(){ int liczba; while( cin >> liczba ) cout << liczba << endl; Jeśli używamy strumienia w warunku, to testujemy jego stan. Test kończy się pomyślnie (zwracana jest wartość niezerowa) tylko wtedy, gdy strumień jest w stanie good.
Dziedziczenie 292 Testowanie stanu strumienia za pomocą funkcji
Dziedziczenie 293 Ustawianie stanu strumienia
Dziedziczenie 294 Strumienie plikowe <fstream.h> Otwieranie istniejącego pliku do odczytu: ifstream wejscie( "c:\\jacek\\dane.txt" ); if(!wejscie ){ cerr << "Nie moge otworzyc pliku!" << endl; exit( 1 ); Otwieranie pliku do zapisu: ofstream wyjscie( "c:\\jacek\\wyniki.txt" ); Otwieranie pliku do zapisu i odczytu: fstream dbase( "c:\\jacek\\rekordy.dat", ios :: in ios :: out ); Zamykanie pliku realizują destruktory odpowiednich klas lub funkcja close().
Dziedziczenie 295 Nieformatowane wejście i wyjście #include <fstream.h> int main( int argc, char *argv[] ){ if( argc!= 3 ){cerr << "Skladnia: kopiuj <src> <dst>\n"; return 1; ifstream src( argv[1] ); if(!src ){ cerr << "Nie mozna otworzyc pliku: " << argv[1] << endl; return 1; ofstream dst(argv[2]); if(!src ){ cerr << "Nie mozna otworzyc pliku: " << argv[2] << endl; return 1; char c; while( src.get( c ) ) dst.put( c ); if(!src.eof() dst.bad() ){ cerr << "Powazny blad!\n"; return 2; return 0;
Dziedziczenie 296 Wprowadzanie tekstów Rozwiązanie ryzykowne! Co będzie, gdy napis przekroczy 17 znaków? #define DLUG 18 #include <iostream.h> void main(){ char buf[dlug]; cin >> buf; cout << buf;
Dziedziczenie 296 Wprowadzanie tekstów Rozwiązanie ryzykowne! Co będzie, gdy napis przekroczy 17 znaków? #define DLUG 18 #include <iostream.h> void main(){ char buf[dlug]; cin >> buf; cout << buf; Bezpieczne wprowadzanie linii tekstu za pomocą funkcji get(). cin.get( buf, DLUG, \n );
Dziedziczenie 297 Wprowadzanie tekstu za pomocą get() Deklaracja:
Dziedziczenie 297 Wprowadzanie tekstu za pomocą get() Deklaracja:istream & get( char * gdzie, int ile, int = \n );
Dziedziczenie 297 Wprowadzanie tekstu za pomocą get() Deklaracja:istream & get( char * gdzie, int ile, int = \n ); Wczytuje zadaną liczbę znaków, chyba że zostanie napotkany znak terminatora (domyślnie: \n ).
Dziedziczenie 297 Wprowadzanie tekstu za pomocą get() Deklaracja:istream & get( char * gdzie, int ile, int = \n ); Wczytuje zadaną liczbę znaków, chyba że zostanie napotkany znak terminatora (domyślnie: \n ). Jeśli na wejściu pozostanie terminator, to będzie on pierwszym nie przeczytanym znakiem strumienia. Dzięki temu można sprawdzać przepełnienie bufora: #include <iostream.h> void main(){ char buf[dlug]; cin.get( buf, DLUG, \n ); char c; if( cin.get( c ) && c!= \n ) cerr << "Napis przekroczyl dlugosc bufora" << endl;
Dziedziczenie 298 Ustalanie i odczyt pozycji strumienia Funkcja Opis ostream& ostream::seekp( streampos ); Ustaw pozycję ostream& ostream::seekp( streamoff, ios::seekdir ); Ustaw pozycję streampos ostream::tellp(); Odczyt pozycji istream& istream::seekg( streampos ); Ustaw pozycję istream& istream::seekg( streamoff, ios::seekdir ); Ustaw pozycję streampos istream::tellg(); Odczyt pozycji g oznacza pozycję odczytu znaku, a p pozycję zapisu. ios :: seekdir oznacza bieżącą pozycję, względem której należy ustawiać nową pozycję strumienia:
Dziedziczenie 298 Ustalanie i odczyt pozycji strumienia Funkcja Opis ostream& ostream::seekp( streampos ); Ustaw pozycję ostream& ostream::seekp( streamoff, ios::seekdir ); Ustaw pozycję streampos ostream::tellp(); Odczyt pozycji istream& istream::seekg( streampos ); Ustaw pozycję istream& istream::seekg( streamoff, ios::seekdir ); Ustaw pozycję streampos istream::tellg(); Odczyt pozycji g oznacza pozycję odczytu znaku, a p pozycję zapisu. ios :: seekdir oznacza bieżącą pozycję, względem której należy ustawiać nową pozycję strumienia:ios :: beg początek pliku
Dziedziczenie 298 Ustalanie i odczyt pozycji strumienia Funkcja Opis ostream& ostream::seekp( streampos ); Ustaw pozycję ostream& ostream::seekp( streamoff, ios::seekdir ); Ustaw pozycję streampos ostream::tellp(); Odczyt pozycji istream& istream::seekg( streampos ); Ustaw pozycję istream& istream::seekg( streamoff, ios::seekdir ); Ustaw pozycję streampos istream::tellg(); Odczyt pozycji g oznacza pozycję odczytu znaku, a p pozycję zapisu. ios :: seekdir oznacza bieżącą pozycję, względem której należy ustawiać nową pozycję strumienia:ios :: beg początek pliku, ios :: cur bieżąca pozycja
Dziedziczenie 298 Ustalanie i odczyt pozycji strumienia Funkcja Opis ostream& ostream::seekp( streampos ); Ustaw pozycję ostream& ostream::seekp( streamoff, ios::seekdir ); Ustaw pozycję streampos ostream::tellp(); Odczyt pozycji istream& istream::seekg( streampos ); Ustaw pozycję istream& istream::seekg( streamoff, ios::seekdir ); Ustaw pozycję streampos istream::tellg(); Odczyt pozycji g oznacza pozycję odczytu znaku, a p pozycję zapisu. ios :: seekdir oznacza bieżącą pozycję, względem której należy ustawiać nową pozycję strumienia:ios :: beg początek pliku, ios :: cur bieżąca pozycja, ios :: end koniec pliku.
Dziedziczenie 299 Binarny odczyt i zapis do pliku Klasę RecTbl poszerzamy o dwie operacje: odczyt_bin i zapis_bin. class RecTbl{ public: // Zapis bazy w formacie binarnym ostream & zapis_bin( ostream & ) const; // Odczyt bazy w formacie binarnym istream & odczyt_bin( istream & ); //... Pozostałe deklaracje private: int rozmiar; int licznik; OsobaInfo * tab; ;
Dziedziczenie 300 Operacja odczytu z pliku binarnego istream & RecTbl :: odczyt_bin( istream & is ){ // Zbadaj rozmiar pliku is.seekg( 0, ios :: end ); // Przesuń wskaźnik na koniec int bajty = is.tellg(); // Odczytaj pozycję // Czy wystarczy miejsca na dane if( bajty / sizeof(osobainfo) > rozmiar ){ // Trzeba powiększyc rozmiar bazy is.seekg( 0, ios :: beg ); // Przesuń wskaźnik na początek is.read( (char *)tab, bajty ); // Wczytaj całą tablicę licznik = bajty / sizeof(osobainfo); return is;
Dziedziczenie 301 Operacja zapisu do pliku binarnego Zapis do pliku binarnego wszystkich rekordów bazy ostream & RecTbl :: zapis_bin( ostream & os ) const{ if( licznik > 0 ) os.write( (char *)tab, licznik*sizeof(osobainfo)); return os; Funkcja do nieformatowanego odczytu: istream & istream :: read( char* gdzie, int ile); Funkcja do nieformatowanego zapisu: ostream & ostream :: write( char* buf, int ile);
Dziedziczenie 302 Przykładowy program void main( int argc, char *argv[] ){ if( --argc ){ ifstream plik_we(*++argv, ios::in ios::binary ); if(!plik_we ){ cerr << "Nie moge otworzyc pliku: " << *argv << endl; exit( 1 ); RecTbl tbl(100); tbl.odczyt_bin( plik_we ); plik_we.close(); tbl.dodaj("abacki", 6759015 ); // Zapis binarny do pliku ofstream plik_wy( *argv, ios::out ios::binary ); if(!plik_wy ){ cerr << "Nie moge otworzyc pliku: " << *argv << endl; exit( 1 ); tbl.zapis_bin( plik_wy );
Dziedziczenie 303 Strumienie napisowe <strstrea.h> Strumień można związać z tablicą znaków w pamięci głównej: #define ROZM 512 char buf[rozm]; ostrstream strwyj( buf, ROZM ); strwyj << "2 + 2 = " << 4; Jeśli nastąpi przepełnienie bufora, strumień automatycznie przejdzie w stan fail. Można użyć taki strumień do formatowania tekstu, którego nie trzeba drukować od razu.
Dziedziczenie 304 Strumienie napisowe przykład #include <strstrea.h> const int ROZM = 256; void main( int argc, char * argv[] ){ char buf[rozm]; ostrstream strwy( buf, ROZM ); strwy << "Ten program nazywa sie: " << *argv++ << " i ma " << --argc << " argumentow" << endl << "Argumenty programu:" << endl; while( argc-- ) strwy << *argv++ << endl; strwy << \0 ; cout << buf << endl;
Dziedziczenie 305 Operatory we/wy dla typów użytkownika class Zesp{ double re, im; public: inline Zesp( double r, double i = 0.0 ) : re( r ), im( i ) { //... // Operator wprowadzania friend istream & operator >> ( istream &, Zesp & ); // Operator wyprowadzania friend ostream & operator << ( ostream &, Zesp & ); ;
Dziedziczenie 306 Reprezentacja liczby zespolonej Liczba zespolona z niezerową częścią urojoną: ( liczba_rzeczywista, liczba rzeczywista ), np. (2.7, 90.5) Liczba zespolona z zerową częścią urojoną może być reprezentowana jak wyżej lub: (liczba_rzeczywista), np. (34.98) lub liczba_rzeczywista, np. 34.98 Przykład poprawnego strumienia wejściowego: 34.56 0 25.78 ( 56.898, 6.5 ) (12.8) 45.21
Dziedziczenie 307 Operator wprowadzania dla typu: Zesp istream & operator >> ( istream & is, Zesp & z){ double r, i = 0.0; char c = \0 ; is >> c; if( c == ( ){ is >> r >> c; if( c ==, ) is >> i >> c; if( c!= ) ) is.clear( ios :: badbit ); else{ is.putback( c ); //Zwraca znak z powrotem do strumienia is >> r; if( is ) z = Zesp( r, i ); return is;
Dziedziczenie 308 Operator wyprowadzania dla: Zesp ostream & operator << ( ostream & os, Zesp & z){ if( z.im!= 0.0 ) os << ( << z.re <<, << z.im << ) ; else os << z.re; return os; void main(){ Zesp z( 0.0 ); while ( cin >> z ) cout << z << endl;
Dziedziczenie 309 Operatory we/wy dla klasy OsobaInfo class OsobaInfo{ friend class RecTbl; // Operator wyprowadzania friend ostream & operator << ( ostream &, OsobaInfo & ); // Operator wprowadzania friend istream & operator >> ( istream &, OsobaInfo & ); //... Pozostałe deklaracje ; // Prosta wersja operatora wprowadzania istream & operator >> ( istream & is, OsobaInfo & oi ){ is >> oi.nazwisko >> oi.tel; return is; // Operator wyprowadzania ostream & operator << ( ostream & os, OsobaInfo & oi ){ os << oi.nazwisko << << oi.tel; return os;
Dziedziczenie 310 Operator >> dla klasy OsobaInfo istream & operator >> ( istream & is, OsobaInfo & oi ){ char c; // Pomiń białe znaki while( is.get( c ) ) if(!isspace( c ) ){ is.putback( c ); break; char * p = oi.nazwisko; int i; // Nazwisko może zawierać tylko litery i znak myślnika - for( i = 0 ; i < DLUG_NAZW && is.get( c ) ; i++, p++ ) if( isalpha( c ) c == - ) *p = c; else break; if( i == DLUG_NAZW ) ++p; *p = \0 ; while( c!= \n &&!isdigit( c ) && is.get( c )) ; if( isdigit( c )){ is.putback( c ); is >> oi.tel; return is;
Dziedziczenie 311 Operator >> dla klasy RecTbl Operator >> zrealizowano jako funkcję zewnętrzną. istream & operator >> ( istream & is, RecTbl & tab ){ char buf[dlug_nazw + 1]; Tele tel; while( is >> buf >> tel ) tab.dodaj( buf, tel ); return is; Użycie w programie głównym. RecTbl tab( 100 ); ifstream plik( "c:\\jacek\\telefony.txt" ); plik >> tab;
Dziedziczenie 312 Operator << dla klasy RecTbl Operator << zrealizowano jako funkcję zewnętrzną. ostream & operator << ( ostream & os, const RecTbl & tab ){ RecTbl :: Itr b = tab.beg(); RecTbl :: Itr e = tab.end(); while( b!= e ){ os << *b << endl; ++b; return os; Wyprowadzenie nazwisk na ekran RecTbl tab(100); //... Wypełnij tablicę nazwiskami cout << tab;
Dziedziczenie 313 Indeks c J. Cichosz Start Projektowanie i programowanie obiektowe