Slides:



Advertisements
Podobne prezentacje
C++ wykład 9 ( ) Szablony.
Advertisements

C++ wykład 4 ( ) Przeciążanie operatorów.
Programowanie wizualne PW – LAB6 Wojciech Pieprzyca.
Programowanie obiektowe PO PO - LAB 4 Wojciech Pieprzyca.
Programowanie obiektowe
1 Dzisiejszy wykład Klasa string wersja prosta wersja ze zliczaniem odwołań Wyjątki Specyfikator volatile.
Programowanie obiektowe PO PO - LAB 6 Wojciech Pieprzyca.
Zmienne i Typy.
Klasy i obiekty.
Static, const, volatile.
Szablony (wzorce) Przykład 1: Szablon klasy -
B. znaki alfabetu D. obrazy
DZIEDZICZENIE · klasy bazowe i klasy pochodne WyświetlAutora( ) Autor
Wskaźniki. Definiowanie wskaźników Wskaźnik może wskazywać na obiekt dowolnego typu. int * w; char * Wsk_Znak; float * Wskaz_Real; Przykłady: Wskaźnik.
Tablice.
C++ wykład 5 ( ) Dziedziczenie.
Programowanie w C Wykład 3
Języki programowania C++
Podstawy programowania PP – WYK3 Wojciech Pieprzyca.
Podstawy programowania PP – LAB4 Wojciech Pieprzyca.
Język ANSI C Operacje we/wy
Czytanie, pisanie i rysowanie – cd.. Jeszcze jeden strumyk PrintStream działa jak PrintWriter, ale: Używa domyślnego (systemowego) kodowania Nie wyrzuca.
#include #include main () { cout
dr Anna Kwiatkowska Instytut Informatyki
Programowanie obiektowe W2
Polsko – Japońska Wyższa Szkoła Technik Komputerowych
Pracę wykonali: Rafał Chmielorz Michał Sporek Jan Nowik
Klasy w C++. Deklaracja klasy class NazwaTwojejKlasy { //w tym miejscu piszemy definicje typów, //zmienne i funkcje jakie mają należeć do klasy. }; //tutaj.
Metody Programowania Wykład
Podstawy programowania II Wykład 2: Biblioteka stdio.h Zachodniopomorska Szkoła Biznesu.
Programowanie obiektowe III rok EiT
Podstawy programowania w języku C i C++
Wskaźnik może wskazywać na obiekt dowolnego typu. int * w; char * Wsk_Znak; float * Wskaz_Float; Przykład: Wskaźnik przechowuje adres obiektu wskazanego.
Podstawy programowania w języku C i C++
Podstawy programowania
Algorytmy rekurencyjne - przykład
Programowanie obiektowe III rok EiT
Informatyka I Wykład 4 Stałe Stałe liczbowe Stałe znakowe Stałe tekstowe Jerzy Kotowski Politechnika Wroclawska var = 5L - 0xA; -5.
Java – coś na temat Klas Piotr Rosik
Jerzy Kotowski Politechnika Wrocławska
Programowanie obiektowe Wykład 3 dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/21 Dariusz Wardowski.
Programowanie obiektowe Wykład 6 dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/14 Dariusz Wardowski.
Programowanie strukturalne i obiektowe
Podstawy informatyki 2013/2014
Podstawy informatyki 2013/2014
PWSZ Gniezno // codefly 2009 Łukasz Tomczak
Kurs języka C++ – wykład 5 ( )
Podstawy programowania
Programowanie strukturalne i obiektowe C++
Programowanie strukturalne i obiektowe C++ Przeładowanie operatorów Robert Nowak.
Kurs języka C++ – wykład 4 ( )
K URS JĘZYKA C++ – WYKŁAD 1 ( ) Łagodne wprowadzenie do języka C++
Programowanie obiektowe Wykład 9 dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/15 Dariusz Wardowski.
Programowanie C++141 Strumienie wejścia/wyjścia ios istreamostream ifstream iostream ofstream istrstream istringstrem ostrstream ostringstream fstream.
Przestrzenie nazw, strumienie. Przestrzenie nazw Przestrzeń nazw – co to takiego? Przestrzeń nazw – co to takiego?namespace Kiedy potrzebujemy przestrzeni.
Wykład 2 Klasa Zesp i jej hermetyzacja 1.Przykład definicji klasy Zesp 2.Zmiana definicji klasy 3.Zmienne i funkcje statyczne PO2-1 / 28.
Wykład 5 Klasa Vec i jej operatory 1.Kategorie operatorów 2.Operatory ogólne - przykłady 3.Operatory specjalne [ ], ( ) oraz –> 4.Operatory new i delete.
Wykład 8 Polimorfizm 1.Funkcje polimorficzne 2.Czyste funkcje wirtualne i klasy abstrakcyjne PO8-1 / 38.
Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi i Pawła Jerzego Matuszyka Podstawy.
Podstawy informatyki Operacje we/wy Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty.
Podstawy informatyki Struktury Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi.
Podstawy informatyki Operatory rzutowania Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały.
Podstawy informatyki Operacje we/wy Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty.
KURS JĘZYKA C++ – WYKŁAD 11 ( )
Podstawy informatyki Operacje we/wy
Operacje na plikach w C++
Wstęp do programowania
Operacje na plikach w C++
Język C++ Typy Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi i Pawła Jerzego.
Język C++ Operacje we/wy
Zapis prezentacji:

Strumienie wejścia/wyjścia ios istream ostream ifstream iostream ofstream istrstream istringstrem ostrstream ostringstream fstream strstream streambuf filebuf stdiobuf strstrambuf stringmbuf Programowanie C++

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 ’#’ 03240 03 Programowanie C++

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 = 010000, // użyj notacji z kropką dziesiętną unitbuf = 020000, // buforowanie... stdio = 040000 }; // ...współpraca z stdio ... }; Programowanie C++

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; } ... }; Ponieważ wszystkie składowe klasy ios są protected więc aby do nich dotrzeć potrzebujemy publicznych funkcji składowych. Standardowo w klasie mamy do dyspozycji funkcje dostępu czyli selektory zwracające stan poszczególnych danych składowych . Przykładowy program pokazuje jakie są domyślne ustawienia poszczególnych składowych: Szerokość pola jest przyjęta na zero, precyzja na sześć co oznacza, że właśnie taka ilość miejsc po przecinku dla zmiennych rzeczywistych jest wyświetlana. Znakiem wypełnienia pustych miejsc jest spacja natomiast wartość flagi oznacza dla strumienia cin, że tylko pierwsza flaga jest ustawiona natomiast dla strumienia cout ustawiona jest flaga pierwsza i oct. Liczba 2 na początku tej wartości jest nieważna. 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 = 200041 Programowanie C++

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 = 200041 Programowanie C++

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; } ... }; Selektory służyły tylko do sprawdzenia stanu poszczególnych ustawień. Oczywiście musimy mieć możliwość zmiany tych ustawień. Do dyspozycji mamy trzy różne sposoby: albo używając funkcji składowych, których nazwy przypominają to, co robią; albo używając bardzo elementarnych funkcji klasy ios ustawiających całe słowo formatów, albo wykorzystując manipulatory. Najpierw o tym pierwszym sposobie. Każda z czterech danych składowych _width, _precision, _fill i _flags może być zmieniona poprzez odpowiedni modyfikator. Funkcja width ustala minimalną liczbę miejsc przeznaczonych na wypisanie danej liczby. Czyli jeśli liczba cyfr znaczących jest większa niż ustalona szerokość to żadnej z tych cyfr znaczących nie zgubimy. Natomiast nie ma możliwości ustalenia maksymalnej liczby znaków na których ma być wypisana liczba – gdyż mogłoby to prowadzić do obcięcia cyfr znaczących. Ten parametr wykorzystywany jest do wypisywania danych w postaci tabel. Funkcja ta ustala szerokość tylko dla następnej operacji we/wy. Jeśli chodzi o strumień wejścia, to dla wczytywanych liczb ten składnik nie ma znaczenia. Natomiast ma znaczenie dla łańcuchów. Pamiętamy, że wczytując tablicę znaków, nie jest sprawdzane przekroczenie zakresu. Pierwsze znaki są wstawiane do tablicy a następne do kolejnych komórek pamięci co może spowodować zmianę istniejących tam informacji. Czyli jest to sposób na ustawienie maksymalnej wczytywanej liczby znaków: np. Char napis [50]; cin.width(sizeof(napis)); cin>>napis; Przykład pokazuje również, że dla 32-bitowych maszyn 16 jest maksymalną liczbą miejsc po przecinku dla typu double i zwiększenie precyzji do 20 spowoduje wyświetlenie śmieci na pozostałych czterech miejscach. Jak widać trzy pierwsze funkcje zwracają wartość, która obowiązywała dotychczas. Funkcja fill pozwala zmienić znak wypełnienia nieznaczących miejsc i w przeciwieństwie do poprzedniej funkcji daje trwały efekt. Podobnie trwały efekt ma ustawienie funkcji precision, która pozwala określić dokładność z jaką mają być wyświetlane na ekranie liczby zmiennopozycyjne. main () { cout.fill('#'); cout.width(40); cout<<"Hello World"<<endl; cout<<"Hello World"<<endl; double pi =3.14159265358979323946; cout<<" pi = "<<pi<<endl; cout.precision(16); cout.precision(20); } ############################Hello World Hello World pi = 3.141593 pi = 3.1415926535897931 pi = 3.1415926535897931599 Programowanie C++

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.flags(oldf); } 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.flags (oldf); } EA 0xEA 234 Programowanie C++

Maski flag formatu class ios { public: const long basefield = dec | oct | hex; const long adjustfield = left | rigth | internal; const long floatfield = scientific | fixed; ... }; main () { int n = 234; cout.setf(ios::hex | ios::uppercase| ios::showbase); cout<<n<<endl; cout.setf(ios::oct | ios::basefield); } 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); } 0XEA 0352 Hello, World. [ ] [ Hello,] [ World.] 0XEA 234 Programowanie C++

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; } cin.rdstate = 0 22 ^Z cin.rdstate = 3 Programowanie C++

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; } cout<<" suma częściowa wynosi "<<sum<<endl; cin.clear(); while (cin>>n) cout<<" suma całkowita wynosi "<<sum<<endl; 40 90 20 ^Z suma częściowa wynosi 150 30 50 ^Z suma całkowita wynosi 230 Programowanie C++

Klasa istream Nieformatowane funkcje wejścia: int get ( ); 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++

Nieformatowane wejście Litwo! Ojczyzno moja Ty jesteś jak zdrowie... ^Z main () { char c; while((c = cin.get() ) != EOF) cout<<c; cout<<endl; } Litwo! Ojczyzno moja Ty jesteś jak zdrowie... ^Z main () { char c; while(cin.get (c) ) cout<<c; cout<<endl; } main () { char buffer[80]; cin.get(buffer,8); cout<<buffer<<endl; cin.get(buffer, sizeof(buffer)); cin.get(buffer,sizeof(buffer),'.'); } Litwo! Ojczyzno moja Litwo! Ojczyzno moja Ty jesteś jak zdrowie... Ty jesteś jak zdrowie Programowanie C++

Nieformatowane wejście c.d. main () { char buffer[80]; cin.getline(buffer,8); cout<<buffer<<endl; cin.getline(buffer, sizeof(buffer)); cin.getline(buffer,sizeof(buffer),'.'); } 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++

Nieformatowane wejście c.d. main () { char buffer[80],c ; cout<<cin.peek( ) <<" , "<< cin.peek( ) <<" ,"; c = cin.peek( ); cout<<c<<", "; cin.get(buffer, 5); 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); } ABCDEFGHIJKLMN ABCDEFGH???????????? read: 8 IJKLEFGH???????????? read: 4 Programowanie C++

Klasa ostream Nieformatowane funkcje wyjścia: int put ( char c ); 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++

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.write("1234567890", 4); } Litwo! Ojczyzno moja Ty jesteś jak zdrowie... ^Z Hello ABCDEF 1234 Programowanie C++

Manipulatory Manipulatory – specjalne funkcje, które wstawiane do strumieni wyglądają jak obiekty i dokonują zmiany sposobu formatowania Operator wstawiania do strumienia: ostream& operator <<(ostream& (*p)(ostream&)) { return (*p)(*this); } Manipulator endl: ostream& endl(ostream& ostr) { ostr.put(‘\n’); ostr.flush(); } Manipulator strumienia to specjalna funkcja składowa klasy, która jeśli jest używana razem z operatorem wstawiania bądź pobierania ze strumienia wygląda jak obiekt. Do tej pory najczęściej korzystaliśmy z manipulatora endl w następujący sposób: cout<<endl; w rzeczywistości jest to wywołanie funkcji endl(). Popatrzmy jak wygląda realizacja tej funkcji. Klasa ostrem zawiera przeładowany operator wstawiania do strumienia w następującej postaci (folia). Parametrem jest wskaźnik do funkcji, która ma jeden parametr typu ostream. W instrukcji cout<<endl; wywoływany jest operator << z parametrem będącym funkcją endl. To jest parametr funkcyjny a więc wskaźnik p wskazuje na funkcję endl, której definicja jest następująca: (folia). Następuje więc wywołanie operatora wstawiania do strumienia ze wskaźnikiem wskazującym na cout<<endl( ) zatem instrukcja return (*p)(*this) oznacza return cout.endl(*this); a ta funkcja wstawia nową linię czyści bufor cout i zwraca cout. W ten sposób pracują wszystkie manipulatory. Programowanie C++

Manipulatory strumieni Najbardziej popularne manipulatory strumieni: Programowanie C++

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++

Zastosowanie manipulatorów ostream & tem(ostream& str){ str<<setprecision(1)<<setiosflags(ios::showpos) <<setiosflags(ios::fixed) <<resetiosflags(ios::scientific); return str; } ostream & wys(ostream& str){ str<<resetiosflags(ios::showpos); ostream & ges(ostream& str){ str<<resetiosflags(ios:: fixed) <<setiosflags(ios:: scientific) <<setprecision(4); main(){ float t=20.47, g=0.09273; int w=3000; cout<<" temperatura = "<<tem<<t <<" wysokość = "<<wys<<w <<" gestość = "<<ges<<g <<endl; } Grębosz podaje taki przykład – załóżmy, że w programie mamy często wypisywać dane takich typów: temperaturę – z dokładnością do jednego miejsca po kropce dziesiętnej i z zaznaczeniem znaku plus lub minus, wysokość – w liczbach całkowitych, (bez znaku plus bo ujemnej być nie może) gęstość – w tzw. notacji naukowej Jeżeli mamy to robić często to zamiast za każdym razem wprowadzać odpowiedni format lepiej zdefiniować własne manipulatory do wyświetlania każdego typu danej. Wtedy w programie głównym wypisywanie tych wartości jest banalne. temperatura = +20.5 wysokość = 3000 gęstość = 9.273e-02 Programowanie C++

Operacje wejścia/wyjścia na plikach Trzy rodzaje strumieni zdefiniowane dla operacji na plikach: ofstream - zapis do plików, ifstream - odczyt z plików, fstream - odczyt i zapis do tego samego pliku 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 ); ifstream infile (" testfile.txt"); // deklaracja zmiennej i otwarcie pliku ifstream infile; // deklaracja zmiennej infile.open("testfile.txt"); if (infile.fail()) { // otwarcie pliku nie powiodło się; //wyświetl komunikat błędu i wróć do programu } if (!infile) {// otwarcie pliku nie powiodło się;} ifstream* infile; //deklaracja wskażnika infile = new ifstream("testfile.txt"); // utworzenie strumienia i otwarcie pliku ifstream infile; // deklaracja zmiennej infile.open("testfile.txt"); // otwarcie pliku Programowanie C++

Operacje wejścia/wyjścia na plikach Zdefiniowanie strumienia ( obiekt klasy ifstream, ofstrem lub iofstream ) Określenie i otwarcie konkretnego pliku Wykonanie operacji we/wy Likwidacja strumienia Jeśli chcemy zapisywać cos do plików lub z nich czytać mamy do dyspozycji klasy ifstream, ofstream i fstream będące pochodnymi klas, które omawialiśmy do tej pory: istream, ostream i iostream. Aby skorzystać z tego fragmentu biblioteki należy do programu dołączyć plik nagłówkowy fstream.h. Skoro te klasy dziedziczą od klas istream i ostream to oznacza to, że mamy do dyspozycji wszystkie cechy i zachowania, o których mówiliśmy do tej pory. Podstawowa różnica polega na tym, że teraz strumienie nie są już predefiniowane – to jasne, bo to my sami musimy zdecydować do jakich plików będziemy pisać lub z jakich czytać. Jest to bardzo proste jak pokazuje przykładowy program. Najpierw definiujemy obiekt klasy ofstream, który nazywa się plik_wyj, następnie poprzez wywołanie funkcji open mamy powiązany strumień z konkretnym plikiem. Coś wstawiamy do strumienia czyli piszemy do pliku, a po zakończeniu działań zamykamy plik. #include <fstream.h> main(){ ostream plik_wyj; plik_wyj.open("pliczek.txt"); plik_wyj<<"Jakis tekst"; plik_wyj.close( ); } Programowanie C++

Otwarcie plików 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: Otwarcia strumienia można dokonać albo za pomocą funkcji open albo za pomocą konstruktorów – w obu przypadkach mamy takie same argumenty. Mamy tutaj postać funkcji open. Pierwszym parametrem jest nazwa pliku podana jako łańcuch znaków. Drugim parametrem jest tryb otwarcia pliku. Oczywiście w tym miejscu nie ma gwiazdek, natomiast wartosć domyślna tego parametru zależy od klasy, z której wywołujemy funkcję open. W klasie ifstream tym trybem jest ios::in, w ofstream jest ios::out, natomiast w klasie fstream nie ma domyślnej wartości. Trybów otwarcia plików jest kilka i nie wszystkie się wykluczają co oznacza, że można ustawić kilka równocześnie. Tryby te są zdefiniowane jako publiczny typ wyliczeniowy w klasie ios. Programowanie C++

Pliki binarne Pliki binarne służą do przechowywania #include <iostream.h> #include <fstream.h> #include ”point.h" main() { clrscr(); char* nazwa="pliktest.000"; fstream plik(nazwa, ios::out|ios::binary); Point xx; if (plik) { plik.write((char *)&xx, sizeof(xx)); xx.Set(2,2); plik.write((char *)&xx, sizeof(xx)); } plik.close(); plik.open(nazwa, ios::in|ios::out|ios::nocreate); if (plik) while(!plik.eof()) {plik.read((char*)&xx,sizeof(xx)); cout<<xx.X()<<" "<<xx.Y()<<endl;} cout<<" poz. wsk. do czytania "<<plik.tellg()/sizeof(xx)<<endl; plik.seekp(plik.tellg()); xx.SetPoint(3,3); plik.write((char *)&xx, sizeof(xx)); plik.seekg(plik.tellp()-sizeof(xx)); plik.read((char*)&xx,sizeof(xx)); cout<<xx.X()<<" "<<xx.Y()<<endl; } Pliki binarne służą do przechowywania rekordów o określonej liczbie bajtów Funkcje składowe read i write służą do zapisu i odczytu określonej liczby bajtów Obie funkcje wymagają dwóch parametrów: pierwszego typu char* , drugiego typu int określającego liczbę lub odczytywanych bajtów. 0 0 2 2 poz.wsk.do czytania 2 3 3 Programowanie C++

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++

Modyfikacja pliku tekstowego #include <fstream.h> #include <stdlib.h> #include <ctype.h> main( int arg, char** argv) { fstream iofile(argv[1], ios::in|ios::out); if (!iofile) { cerr<<"Error: nie można otworzyc pliku"<<endl; exit(1); } char c; while( c=iofile.get())!=EOF) if (islower(c) { iofile.seekp(-1,ios:::cur); iofile.put(toupper(c)); iofile.close( ); Niniejszy program przedstawia przykład wykorzystania dostępnych w C++ strumieni, które równocześnie umożliwiają odczyt i zapis do pliku. Plik nagłówkowy stdlib.h jest potrzebny by skorzystać z funkcji exit, natomiast ctype aby wykorzystać funkcje islower i toupper. Najpierw definiujemy strumień, który będzie powiązany z plikiem o nazwie przekazywanej przez listę argumentów programu. Załóżmy, że program nazywa się modyfikuj. W pierwszej instrukcji widzimy wykorzystany operator !( ), który był zdefiniowany w klasie ios, jeśli otwarcie pliku nie powiodło się, to program kończy działanie wcześniej przesyłając komunikat do standardowego strumienia błędów cerr. Jeśli natomiast plik został otwarty, to wykonujemy w pętli tak długo aż napotkamy koniec pliku pobieranie znaku, sprawdzanie czy jest to mała litera i jeśli tak to zamiana na dużą. Ta zamiana odbywa się poprzez wykorzystanie funkcji seekp – ustawienie wskaźnika wstawiania o jeden znak wcześniej od aktualnej pozycji. Inw.txt Litwo! Ojczyzno moja Ty jesteś jak zdrowie... modyfikuj Inw.txt LITWO! OJCZYZNO MOJA TY JESTEŚ JAK ZDROWIE... Programowanie C++

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 <class T> 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); Date d1,d2(1999,9,9); cout<<"d1 = "<<d1<<" d2 = "<<d2<<endl; swap(d1,d2); } m = 22 n = 33 m = 33 n = 22 d1 = 2000 1 17 d2 = 1999 9 9 d1 = 1999 9 9 d2 = 2000 1 17 Programowanie C++

Szablony klas Szablony klas działają jak szablony funkcji generując klasy. template <class T,...> class X {...}; Funkcje składowe szablonu klasy są szablonami funkcji o takim samym nagłówku jak szablon klasy. template <class T, int n> class X{}; main( ) { X <float, 22> x1; //O.K. const int n = 44; X<char, n> x2; //O.K. int m = 66; X <short, m> x3; //ERROR } template <class T> class X { T square (T t) { return t*t; } }; template <class T> T square (T t) { return t*t; } Programowanie C++

Szablon klasy stos template <class T> 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<int> stosint(5); Stack<Data> 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( ); } 2 13 2000 1 17 Programowanie C++

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 T> class Vector{ protected: T* data; unsigned size; void copy(const Vector<T>&); public: Vector (unsigned n = 10) : size(n), data( new T[size]) { } Vector ( const Vector<T>& other) : size(other.size), data( new T[size]) { copy(other); } ~Vector {delete [ ] data;} Vector<T>& operator = (const Vector<T>&); T& operator [ ] (unsigned i) const {return data[ i ];} usigned Size( ) const {return size;} }; Programowanie C++

Definicja funkcji składowych template <classT> Vector<T>& Vector<T>::operator = (const Vector<T>& other) { size = other.size; data = new T[size]; copy( other); return this*; } template <class T> void Vector<T>::copy( const Vector<T>& other) unsigned min_size = (size < other.size ? size : other.size); for (int i =0; i<min_size; i++) data[i] = other.data[i]; Vector<short> v; v[5] = 34; Vector<short> w = v, x(3); cout<<w.size( ); Programowanie C++

Dziedziczenie szablonów Dziedziczenie szablonów klas działa tak samo jak dziedziczenie zwykłych klas. template <class T> class Array : public Vector<T>{ protected: int i0; public: Array(int i, int j): i0(i), Vector<T>(j-i+1) { } Array(const Array<T>& other): i0(other.i0), Vector<T>(other) { } T& operator [ ] (int i) const { return Vector<T>::operator [ ] (i-i0); } int firstSubscript( ) const { return i0;} int lastSubscript ( ) const { return i0+size - j; } }; #include<iostream.h> #include "Array.h" main ( ) { Array<float> 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( ) = 3 1..3 x[1] = 2.22 x[2] = 3.33 x[3] = 4.44 Programowanie C++

Szablony jako parametry szablonów Ponieważ szablony klas pracują jak zwykłe klasy to można je przekazywać jako parametry innych szablonów. Stack <Vector<int> > a; template <class T > class Matrix{ protected: Vector<Vector<T>*> row; public: Matrix( unsigned r =1, unsigned c=1) : row { for (int i=0; i<r; i++) row[i] = new Vector<T> (c); } ~Matrix () { for (int i = 0; i<row.size(); i++) delete row[i]; } Vector<T>& operator [ ](unsigned i) const { return *row[i]; } unsigned rows() { return row.size( ) } unsigned columns () { return row[0] -> size( ); } }; main ( ) { Matrix<float> 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 0.0 0.1 0.2 1.0 1.1 1.2 Programowanie C++

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. data 12 t template <class T> class ListNode { friend class List<T>; protected: T data; ListNode* next; public: ListNode(T& t, ListNode<T>* p): data(t), next(p) { } }; 12 p next int ListNode< int > template <class T> class List { protected: ListNode<T>* first; ListNode<T>* newNode( T& t, ListNode<T>* p) { ListNode<T>* q = new ListNode<T>(t,p); return q; } ... Programowanie C++

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 <class T> List <T>::~List ( ) { ListNode<T>* temp; for (ListNode<T>* p = first; p; ) temp = p; p = p->next; delete temp; } Funkcja insert tworzy nowy węzeł i wstawia go na początek listy: template <class T> void List <T>::insert (T t) { ListNode<T>* p = newNode(t,first); first = p; } Programowanie C++

Listy c.d. 3 -> 2 -> 1 -> 0 -> * Usunięto 2 #include <iostream.h> #include "List.h" main( ) { List<int> 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; } template <class T> int List <T>::remove ( T& t) { if (isEmpty()) return 0; t = first->data; ListNode<T>* p = first; first = first->next; delete p; return 1; } void List <T>::print ( ) for (ListNode<T>* p = first; p; p = p ->next) cout<<p -> data << "-> ”; cout<<”* \n”; 3 -> 2 -> 1 -> 0 -> * Usunięto 2 2 -> 1 -> 0 -> * data 2 next data 1 next data next Programowanie C++

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 T> 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++

Szablon iteratora dla szablonu klasy List // plik ListIter.h #include ”List.h” #include ”Iterator.h” template <class T> class ListIter: public Iterator<T> { protected: ListNode<T>* current; ListNode<T>* previous; List<T>& list; public: ListIter(List<T>& 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 <class T> int ListIter<T>::operator ! ( ) { if (current==NULL) if (previous==NULL) current=list.first; else current=previous->next; return (current!=NULL); } if (!it)... template <class T> int ListIter<T>::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++

#include "List.h" #include "ListIter.h" #include "Date.h" main( ) { List<Date> Daty; ListIter<Date> it(Daty); Date today; it.insert(today); today.Forth(); it++; today.Back(); Daty.print(); Date my(1994,4,19); it.reset(); it=my; it.remove(); for (it.reset(); !it; it++) {Date temp=it(); temp.Forth(); it = temp; } } template <class T> void ListIter<T>::insert(T t) { ListNode<T>* p=list.newNode(t,0); if (list.isEmpty( ) ) list.first=p; else { p->next= current->next; current->next=p; } } void ListIter<T>:remove( ) { if (current==list.first) list.first = current->next; else previous->next= current->next; delete current; current = 0; 2000 3 28 -> 2000 3 29 -> 2000 3 28 ->* 2000 3 29 -> 1994 4 20 ->* Programowanie C++

Przyjaciel Listy Lista może posiadać więcej niż jeden iterator: // List.h template <class T> class List { friend class ListIter<T>; //.... }; class ListNode { friend class List<T>; Lista może posiadać więcej niż jeden iterator: Iteratory są od siebie niezależne. List<float> list; ListIter<float> it1(list), it2(list),it3(list); it1.insert(11.01); it1++; it1.insert(22.02); it1.insert(33.03); for (it2.reset(); !it2; it2++) it2=10*it2; it3=it1; Programowanie C++