Programowanie C++141 Strumienie wejścia/wyjścia ios istreamostream ifstream iostream ofstream istrstream istringstrem ostrstream ostringstream fstream strstream streambuf filebufstdiobuf strstrambuf stringmbuf
Programowanie C++142 Klasa ios class ios { public: typedef unsigned long fmtflags; // 32-bitowy łańcuch bitowy typedef unsigned char iostate;// 8-bitowy łańcuch bitowy protected: streambuf* _strbuf;// wskaźnik do bufora ostream* _tie;// wskaźnik do ostream dołączonego do istream int _width;// szerokość pola wyjściowego int _prec;// dokładność dla float char _fill;// znak wypełnienia pustych pól fmtflags _flags;// flagi formatowania iostate _state;// aktualny stan io ios(streambuf* _strbuf = 0, ostream* _tie = 0); X ~ios();... }; _width _prec _fill _flags _state _strbuf _tie 15 9 ’#’
Programowanie C++143 Flagi formatowania class ios { public: enum { skipws= 01,// pomiń białe znaki (domyślne) left= 02,// wyrównanie lewostronne right= 04,// wyrównanie prawostronne (domyślne) internal= 010,// wyrównanie lewo i prawostronne dec= 020,// konwersja dziesiątkowa oct = 040,// konwersja ósemkowa hex= 0100,// konwersja szesnastkowa showbase= 0200,// pokaż podstawę konwersji showpoint= 0400,// pokaż kropkę dziesiętną uppercase = 01000,// duże litery w zapisie liczb showpos = 02000,// użyj + z liczbami dodatnimi scientific = 04000,// użyj notacji naukowej dla float i double fixed= ,// użyj notacji z kropką dziesiętną unitbuf= ,// buforowanie... stdio= }; //...współpraca z stdio... };
Programowanie C++144 Selektory klasy ios class ios { public: streambuf* rdbuf () const { return _strbuf ; } ostream* tie () const { return _tie; } int width () const { return _width; } int precision () const { return _prec; } char fill () const { return _fill; } long flags () const { return _flags; } int rdstate () const { return _state; }... }; main () { cout<<"cout.width = "<< cout.width( ) <<endl; cout<<"cout.precision = " << cout.precision( )<<endl; cout<<"cout.fill= "<< cout.fill( )<<endl; cout<<"cin.flags= "<<cin.flags()<<endl; cout<<"cout.flags= "<<cout.flags()<<endl; } cout.width = 0 cout.precision = 6 cout.fill= cin.flags= 1 cout.flags=
Programowanie C++145 Modyfikatory klasy ios class ios { public: int width (int w) { int t = _width; _width = w; return t; } int precision (int p) {int t = _precision; _precision = t; return t; } char fill (char c) { char t = _fill; _fill = c; return t; } long flags (long f) { long t = _flags; _flags = f; return t; }... }; ############################Hello World Hello World pi = pi = pi = main () { cout.fill('#'); cout.width(40); cout<<"Hello World"<<endl; double pi = ; cout<<" pi = "<<pi<<endl; cout.precision(16); cout<<" pi = "<<pi<<endl; cout.precision(20); cout<<" pi = "<<pi<<endl; }
Programowanie C++146 Zmiana flag formatowania main () { int n = 234; long oldf = cout.flags(ios::hex | ios::uppercase); cout<<n<<endl; cout.flags(ios::hex | ios::showbase); cout<<n<<endl; cout.flags(oldf); cout<<n<<endl; } class ios { public: long setf (long f) ; long setf( long f, long mask); long unsetf(long mask);... }; EA 0xea 234 main () { int n = 234; long oldf = cout.setf (ios::hex | ios::uppercase); cout<<n<<endl; cout.setf (ios::hex | ios::showbase); cout<<n<<endl; cout.flags (oldf); cout<<n<<endl; } EA 0xEA 234
Programowanie C++147 main () { char buffer[80]; cin.unsetf(ios::skipws); //czyści domyślneustawienie flagi cin>>buffer; cout<<"["<<buffer<<"]\n"; int n = 234; cout.setf(ios::hex | ios::uppercase| ios::showbase; cout<<n<<endl; cout.usetf( ios::basefield); cout<<n<<endl; } Maski flag formatu class ios { public: const long basefield = dec | oct | hex; const long adjustfield = left | rigth | internal; const long floatfield = scientific | fixed;... }; Hello, World. [ ] [ Hello,] [ World.] 0XEA 234 main () { int n = 234; cout.setf(ios::hex | ios::uppercase| ios::showbase); cout<<n<<endl; cout.setf(ios::oct | ios::basefield); cout<<n<<endl; } 0XEA 0352
Programowanie C++148 Zmienne stanu klasy ios class ios { public: enum { goodbit= 0,// wszystko ok eofbit= 01,// koniec pliku failbit= 02,// ostatnia operacja zakończona niepomyślnie badbit= 04 };// niewłaściwa operacja... }; Dostępne selektory: good(), eof(), fail(), bad(), rdstate() main () { cout<<" cin.rdstate = "<<cin.rdstate()<<endl; int n; cin>>n; cout<<" cin.rdstate = "<<cin.rdstate()<<endl; } cin.rdstate = 0 22 cin.rdstate = 0 ^Z cin.rdstate = 3
Programowanie C++149 Operatory dla stanu ios class ios { public: operator void* () const;// operator konwersji int operator! () const; void clear (int );// modyfikator - ustawia nowe słowo stanu strumienia... }; main () { int n, sum=0; cin>>n; while (cin) {// pętla będzie wykonywana tak długo dopóki _state ==0 sum+=n; cin>>n; } cout<<" suma częściowa wynosi "<<sum<<endl; cin.clear(); while (cin>>n) sum+=n; cout<<" suma całkowita wynosi "<<sum<<endl; } ^Z suma częściowa wynosi ^Z suma całkowita wynosi 230
Programowanie C++150 Klasa istream class istream : virtual public ios { //...} zdefiniowanie ios jako wirtualnej klasy bazowej ułatwia wielokrotne dziedziczenie, które posiada klasa iostream Strumień cin oraz operator >> klasy istream obsługują formatowane operacje wejścia. Nieformatowane funkcje wejścia: int get ( ); istream& get ( char& c ); istream& get ( char* buffer, int n, char delim = ’\n’ ); istream& getline ( char* buffer, int n, char delim = ’\n’); istream& ignore ( int n = 1, int delim = EOF); int peek ( ); istream& putback (char c); istream& read ( char* buffer, int n); istream& read ( unsigned char* buffer, int n); int gcount ( );
Programowanie C++151 Nieformatowane wejście main () { char c; while((c = cin.get() ) != EOF) cout<<c; cout<<endl; } main () { char c; while(cin.get (c) ) cout<<c; cout<<endl; } Litwo! Ojczyzno moja Ty jesteś jak zdrowie... ^Z Litwo! Ojczyzno moja Ty jesteś jak zdrowie... ^Z main () { char buffer[80]; cin.get(buffer,8); cout<<buffer<<endl; cin.get(buffer, sizeof(buffer)); cout<<buffer<<endl; cin.get(buffer,sizeof(buffer),'.'); cout<<buffer<<endl; } Litwo! Ojczyzno moja Litwo! Ojczyzno moja Ty jesteś jak zdrowie... Ty jesteś jak zdrowie
Programowanie C++152 Nieformatowane wejście c.d. main () { char buffer[80]; cin.getline(buffer,8); cout<<buffer<<endl; cin.getline(buffer, sizeof(buffer)); cout<<buffer<<endl; cin.getline(buffer,sizeof(buffer),'.'); cout<<buffer<<endl; } Litwo! Ojczyzno moja Litwo! Ojczyzno moja Ty jesteś jak zdrowie... Ty jesteś jak zdrowie main () { int month,year; cout<<"Podaj datę (mm/dd/rrrr): "; cin>>month; cin.ignore();// zjada '/' cin.ignore(80,'/');//zjada "dd/", lub "d/" lub "/" cin>>year; cout<<"Miesiąc = "<<month<<”, Rok = "<<year <<endl; } Podaj datę (mm/dd/rrrr): 1/10/2000 Miesiąc = 1, Rok = 2000
Programowanie C++153 Nieformatowane wejście c.d. main () { char buffer[80],c ; cout<<cin.peek( ) <<", "<< cin.peek( ) <<","; c = cin.peek( ); cout<<c<<", "; cin.get(buffer, 5); c = cin.peek( ); cout<<c <<", "<< cin.peek( ) <<", "<< cin.peek( ) <<endl; cin.putback('Z'); cin.putback('Y'); cin.get(buffer,5); cout<<buffer<<endl; } ABCDEFG 65, 65, A, E, 69, 69 YZEF main () { char buffer[] = "????????????????????"; cin.read(buffer, 8); cout<<buffer<<" read: "<<cin.gcount( ) <<endl; cin.read(buffer, 4); cout<<buffer<<" read: "<<cin.gcount( ) <<endl; } ABCDEFGHIJKLMN ABCDEFGH???????????? read: 8 IJKLEFGH???????????? read: 4
Programowanie C++154 Klasa ostream class ostream : virtual public ios { //...} Strumienie: cout // standardowe urządzenie wyjścia cerr // standardowe urządzenie wyjścia dla komunikatów błędów (niebuforowany) clog // jak wyżej, strumień buforowany wraz z operatorem << obsługują formatowane wyjście. Nieformatowane funkcje wyjścia: int put ( char c ); ostream& put ( char c ); ostream& write ( const char* buffer, int n); ostream& write ( const unsigned char* buffer, int n );
Programowanie C++155 Nieformatowane wyjście main () { char c ; while(cin.get (c) ) cout.put(c); cout<<endl; cout.put('H'). put('e'). put('l'). put('l'). put('o'). put('\n'); cout.write("ABCDEFGHIJKLMNOPRSTUWXYZ",8); cout<<endl; cout.write(" ", 4); cout<<endl; } Litwo! Ojczyzno moja Ty jesteś jak zdrowie... ^Z Hello ABCDEF 1234
Programowanie C++156 Manipulatory strumieni Najbardziej popularne manipulatory strumieni:
Programowanie C++157 Definiowanie manipulatorów Manipulatory strumieni definiowane są zgodnie z następującymi prototypami: - manipulatory bezparametrowe ios& f( ios& ostr); ostream& f( ostream& ostr ); istream& f ( istream& istr); - manipulatory z parametrem ios& f( ios& ostr, int n ); ostream& f( ostream& ostr, int n ); istream& f ( istream& istr, int n ); ostream& beep(ostream& ostr) { return ostr<<„\a”; } main ( ) { cout<<beep; }
Programowanie C++158 Operacje wejścia/wyjścia na plikach Otwarcia plików wejściowych i wyjściowych można dokonać za pomocą konstruktorów lub funkcji open (mają takie same parametry): void open ( char* name, int mode = ***, int prot = filebuf::openprot ); Tryby otwarcia plików:
Programowanie C++159 Wskaźnik pozycji w pliku Każdy plik posiada swój wskaźnik (albo do czytania, albo do pisania, albo dwa niezależne wskaźniki jeden do czytania a drugi do pisania). Wskaźniki te są typu streampos streampos tellg( );// funkcja klasy istream pokazuje jakie jest położenie wskaźnika do czytania streampos tellp( ); // funkcja klasy ostream pokazuje położenie wskaźnika pisania enum seek_dir // typ wyliczeniowy zdefiniowany w klasie ios określający punkt odniesienia { beg, // początek cur, // aktualna pozycja end }; // koniec istream& seekg (streampos, seek_dir = ios::beg); ostream& seekp(streampos, seek_dir = ios::beg); Plik w C++ może być otwarty jednocześnie do zapisu i oczytu. Korzystamy wówczas z klasy fstream: fstream strum(„plik.txt”, ios::in | ios::out)
Programowanie C++160 Funkcje wirtualne main () { DatePolish today; DatePolish::SetFormat(DatePolish::TEXT); cout<<„\n Funkcja Write : „; today.Write(); cout<<„\n Funkcja Display ; „; today.Display; Date tomrrow(2000,1,11); tomorow.Display(); cout<<„\n Funkcja Display ; „; tomorow.Display(); ; } Funkcje wirtualne gwarantują tzw. dynamiczne wiązanie czyli wywołanie funkcji jest odłożone do czasu realizacji programu i jest zależne od obiektu, na rzecz którego dana funkcja jest wywoływana. Funkcja Write : 10 Styczeń 2000 Funkcja Display : Funkcja Display: class Date {... virtual Write (ostream& output = cout) const... }; Funkcja Write : 10 Styczeń 2000 Funkcja Display : 10 Styczeń 2000 Funkcja Display :
Programowanie C++161 Polimorfizm Polimorfizm - pozwala by obiekty różnych typów powodowały różne działanie w wywołaniu tej samej funkcji. Jest to możliwe dzięki temu, że wskaźnik do obiektu klasy bazowej może również pokazywać na obiekty klas pochodnych. Aby uzyskać wiązanie dynamiczne parametry muszą być przekazywane przez wskaźnik bądź referencję Słowo virtual pojawia się tylko w deklaracji funkcji w klasie podstawowej, nie musi pojawić w klasie pochodnej Jeśli klasa bazowa deklaruje funkcję wirtualną to musi zawierać jej definicję nawet jeśli ciało funkcji jest puste Klasa pochodna nie musi definiować ponownie funkcji wirtualnej, wówczas domyślnie wywoływana jest funkcja z klasy bazowej Klasa pochodna we własnej definicji nie może zmieniać typu zwracanego przez funkcję wirtualną
Programowanie C++162 Wirtualne destruktory Destruktory definiujemy jako funkcje wirtualne! class X { private: int* p; public: X() {p = new int[2]; cout<<” X(). ”;} ~X() { delete [] p; cout<<”~X (). \n”;} }; class Y: public X{ private: int* q; public: Y() {q = new int[100]; cout<<”Y() : Y::q = ”<<q<<”. ”;} ~Y() { delete [] q; cout<<”~Y() ”;} }; main ( ) { for (int i = 0; i<3; i++) { X* r = new Y; delete r; } X (). Y() : Y::q = 0x0d18. ~X(). X (). Y() : Y::q = 0x0de4. ~X(). X (). Y() : Y::q = 0x0eb0. ~X(). virtual ~X() { delete [] p; cout<<”~X (). \n”;} X (). Y() : Y::q = 0x0d24. ~Y() ~X().
Programowanie C++163 Czyste funkcje wirtualne i klasy abstrakcyjne Media Audio BookPeriodical CDMagazineNewspaperJournalTapeRecord Czysta funkcja wirtualna - funkcja nie mająca w swojej klasie implementacji. virtual void f( ) = 0; Abstrakcyjna klasa bazowa - klasa posiadająca jedną lub więcej czystych funkcji wirtualnych. class Media{ protected: String title; public: virtual void print( ) = 0; virtual char* id( ) = 0; }; class Book: public Media{ private: String author, publisher,isbn; public: void print ( ) { cout<<title<<" by "<<author;} void id ( ) { cout<<isbn; } };
Programowanie C++164 Szablony funkcji Szablon - abstrakcyjny przepis na tworzenie konkretnego kodu. T jest parametrem szablonu Szablon musi być zdefiniowany w zakresie globalnym. void swap( int& n, int& m) { int temp = n; n = m; m = temp; } void swap(Date& d1, Date& d2) { Date temp = d1; d1 = d2; d2 = temp; } template void swap(T& x, T& y) { T temp = x; x = y; y = temp; } main ( ) { int m = 22, n = 33; cout<<" m = "<<m<<" n = "<<n<<endl; swap(m,n); cout<<" m = "<<m<<" n = "<<n<<endl; Date d1,d2(1999,9,9); cout<<"d1 = "<<d1<<" d2 = "<<d2<<endl; swap(d1,d2); cout<<"d1 = "<<d1<<" d2 = "<<d2<<endl; } m = 22 n = 33 m = 33 n = 22 d1 = d2 = d1 = d2 =
Programowanie C++165 Szablony klas Szablony klas działają jak szablony funkcji generując klasy. template class X {...}; Funkcje składowe szablonu klasy są szablonami funkcji o takim samym nagłówku jak szablon klasy. template class X{}; main( ) { X x1;//O.K. const int n = 44; X x2;//O.K. int m = 66; X x3;//ERROR } template class X { T square (T t) { return t*t; } }; template T square (T t) { return t*t; }
Programowanie C++166 Szablon klasy stos template class Stack { private: int size; int top; T* data; public: Stack( int s = 100): size(s); top = -1; { data = new T[size]; } ~Stack( ) {delete [ ] data}; void push (const T& x) {data[++top] = x; } T pop() { return data[top--];} int isEmpty( ) const {return top = = -1;} int isFull( ) const { return top = = size - 1; } }; main ( ) { Stack stosint(5); Stack stosdata(10); Data x, y(2000,1,17); stosint.push(13); stosint.push(2); stosdata.push(x); stosdata.push(y); cout<<stosint.pop( )<<„ „<<stosint.pop( )<<endl; stosdata.pop( ).Display( ); }
Programowanie C++167 Pojemniki Pojemnik to obiekt, który zawiera inne obiekty (np.tablica, stos). Klasa pojemnikowa (klasa - pojemnik) to klasa, której obiekty są pojemnikami. Pojemnik zwany jest homogenicznym jeśli wszystkie jego obiekty są tego samego typu lub heterogenicznym w przeciwnym przypadku. template class Vector{ protected: T* data; unsigned size; void copy(const Vector &); public: Vector (unsigned n = 10) : size(n), data( new T[size]) { } Vector ( const Vector & other) : size(other.size), data( new T[size]) { copy(other); } ~Vector {delete [ ] data;} Vector & operator = (const Vector &); T& operator [ ] (unsigned i) const {return data[ i ];} usigned Size( ) const {return size;} };
Programowanie C++168 Definicja funkcji składowych template Vector & Vector ::operator = (const Vector & other) { size = other.size; data = new T[size]; copy( other); return this*; } template void Vector ::copy( const Vector & other) { unsigned min_size = (size < other.size ? size : other.size); for (int i =0; i<min_size; i++) data[i] = other.data[i]; } Vector v; v[5] = 34; Vector w = v, x(3); cout<<w.size( );
Programowanie C++169 Dziedziczenie szablonów Dziedziczenie szablonów klas działa tak samo jak dziedziczenie zwykłych klas. template class Array : public Vector { protected: int i0; public: Array(int i, int j): i0(i), Vector (j-i+1) { } Array(const Array & other): i0(other.i0), Vector (other) { } T& operator [ ] (int i) const { return Vector ::operator [ ] (i-i0); } int firstSubscript( ) const { return i0;} int lastSubscript ( ) const { return i0+size - j; } }; #include #include "Array.h" main ( ) { Array x(1,3); x[1] = 2.22; x[2] = 3.33; x[3] = 4.44; cout<"x.Size( ) = "<<x.Size( )<<endl; cout<<x.fistSubscript( )<<".."<<lastSubscript( )<<endl; for (int i = 1, i<=3, i++) cout<<"x["<<i<<"] = "<<x[i]<<endl; } x.Size( ) = x[1] = 2.22 x[2] = 3.33 x[3] = 4.44
Programowanie C++170 Szablony jako parametry szablonów Ponieważ szablony klas pracują jak zwykłe klasy to można je przekazywać jako parametry innych szablonów. Stack > a; template class Matrix{ protected: Vector *> row; public: Matrix( unsigned r =1, unsigned c=1) : row { for (int i=0; i (c); } ~Matrix () { for (int i = 0; i<row.size(); i++) delete row[i]; } Vector & operator [ ](unsigned i) const { return *row[i]; } unsigned rows() { return row.size( ) } unsigned columns () { return row[0] -> size( ); } }; main ( ) { Matrix a(2,3); a[0][0] = 0.0; a[0][1] = 0.1; a[0][2] = 0.2; a[1][0] = 1.0; a[1][1] = 1.1; a[1][2] = 1.2; cout<<"Macierz ma "<<a.rows( )<<" wiersze i " <<a.columns( ) <<" kolumny.\n"; for (int i=0; i<2; i++) { for (int j=0; j<3; j++) cout<<a[i][j]<<" "; cout<<endl; } Macierz ma 2 wiersze i 3 kolumny
Programowanie C++171 Szablon klasy dla list jednokierunkowych Listy - struktury pozwalające na dynamiczną alokację pamięci, tworzone jako połączony ciąg węzłów, z których każdy zawiera dane składowe oraz wskaźnik do następnego węzła. template class ListNode { friend class List ; protected: T data; ListNode* next; public: ListNode(T& t, ListNode * p): data(t), next(p) { } }; template class List { protected: ListNode * first; ListNode * newNode( T& t, ListNode * p) { ListNode * q = new ListNode (t,p); return q; } int t data 12 next p ListNode
Programowanie C++172 Funkcje składowe szablonu listy Konstruktor domyślny ustawia wskaźnik first na 0 Destruktor będzie likwidował całą listę:... public : List ( ) : first(0) { } ~List ( ); void insert (T t); int remove (T& t); int isEmpty ( ) { return first == 0;} void print ( ); }; template List ::~List ( ) { ListNode * temp; for (ListNode * p = first; p; ) { temp = p; p = p->next; delete temp; } Funkcja insert tworzy nowy węzeł i wstawia go na początek listy: template void List ::insert (T t) { ListNode * p = newNode(t,first); first = p; }
Programowanie C++173 template int List ::remove ( T& t) { if (isEmpty()) return 0; t = first->data; ListNode * p = first; first = first->next; delete p; return 1; } template void List ::print ( ) { for (ListNode * p = first; p; p = p ->next) cout data ”; cout<<”* \n”; } #include #include "List.h" main( ) { List liczby; liczby.insert(0); liczby.insert(1); liczby.insert(2); liczby.insert(3); liczby.print( ); int x; liczby.remove(x); cout<<"Usunięto "<<x<<endl; liczby.print( ); } Listy c.d. 3 -> 2 -> 1 -> 0 -> * Usunięto 2 2 -> 1 -> 0 -> * data 2 next data 1 next data 0 next
Programowanie C++174 Iteratory Iterator - obiekt mający zdolność poruszania się po elementach pojemników; działający jak wskaźnik pokazujący w danym momencie jeden element należący do pojemnika. Podstawowe operacje iteratora: inicjalizacja iteratora na początkowej pozycji pojemnika, pobranie wartości danych znajdujących się we wskazywanej pozycji, zmiana wartości danych na określonej pozycji, określenie czy we wskazywanej przez iterator pozycji znajduje się jakaś wartość, przesunięcie do następnej pozycji pojemnika. // Iterator.h template class Iterator { public: virtual int reset( ) = 0; virtual T operator ( )( ) = 0; virtual void operator = (T t) = 0; virtual int operator ! ( ) = 0; virtual int operator ++( ) =0; };
Programowanie C++175 Szablon iteratora dla szablonu klasy List // plik ListIter.h #include ”List.h” #include ”Iterator.h” template class ListIter: public Iterator { protected: ListNode * current; ListNode * previous; List & list; public: ListIter(List & l):list(l) {reset( );} virtual void reset( ) {previous = NULL; current = list.first;} virtual T operator ( ) ( ) {return current->data;} virtual void operator = (T t) {current->data=t;} virtual int operator ! ( ) ; virtual int operator ++( ) ; void insert (T t); void preInsert(T t); void remove( ); }; template int ListIter ::operator ! ( ) { if (current==NULL) if (previous==NULL) current=list.first; else current=previous->next; return (current!=NULL); } if (!it)... template int ListIter ::operator ++ ( ) { if (current==NULL) if (previous==NULL) current=list.first; else current=previous->next; else { previous=current; current=current->next; } return (current!=NULL); } for (it.reset(); !it; it++)...
Programowanie C++176 #include "List.h" #include "ListIter.h" #include "Date.h" main( ) { List Daty; ListIter it(Daty); Date today; it.insert(today); today.Forth(); it++; it.insert(today); today.Back(); it++; it.insert(today); Daty.print(); Date my(1994,4,19); it.reset(); it++; it=my; it++; it.remove(); for (it.reset(); !it; it++) {Date temp=it(); temp.Forth(); it = temp; } Daty.print(); } template void ListIter ::insert(T t) { ListNode * p=list.newNode(t,0); if (list.isEmpty( ) ) list.first=p; else { p->next= current->next; current->next=p; } } template void ListIter :remove( ) { if (current==list.first) list.first = current->next; else previous->next= current->next; delete current; current = 0; } > > >* > >*
Programowanie C++177 Przyjaciel Listy Lista może posiadać więcej niż jeden iterator: Iteratory są od siebie niezależne. // List.h template class List { friend class ListIter ; //.... }; template class ListNode { friend class List ; friend class ListIter ; //.... }; List list; ListIter it1(list), it2(list),it3(list); it1.insert(11.01); it1++; it1.insert(22.02); it1++; it1.insert(33.03); for (it2.reset(); !it2; it2++) it2=10*it2; it3=it1;