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

Strumienie wejścia/wyjścia

Embed Size (px)

DESCRIPTION

Strumienie wejścia/wyjścia. ios istreamostream ifstream iostream ofstream istrstream istringstrem ostrstream ostringstream fstream strstream streambuf filebufstdiobuf strstrambuf stringmbuf. Klasa ios. - PowerPoint PPT Presentation

Citation preview

Page 1: Strumienie wejścia/wyjścia

Programowanie C++ 1

Strumienie wejścia/wyjścia

ios

istream ostream

ifstream iostream ofstream

istrstream istringstrem ostrstream ostringstream

fstream strstream

streambuf

filebuf stdiobuf

strstrambuf stringmbuf

Page 2: Strumienie wejścia/wyjścia

Programowanie C++ 2

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

159

’#’03240

03

Page 3: Strumienie wejścia/wyjścia

Programowanie C++ 3

Flagi formatowaniaclass 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

...

};

Page 4: Strumienie wejścia/wyjścia

Programowanie C++ 4

Selektory klasy iosclass 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

Page 5: Strumienie wejścia/wyjścia

Programowanie C++ 5

Modyfikatory klasy iosclass 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 WorldHello Worldpi = 3.141593pi = 3.1415926535897931pi = 3.1415926535897931pi = 3.1415926535897931599

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<<" pi = "<<pi<<endl; cout<<" pi = "<<pi<<endl; cout.precision(20); cout<<" pi = "<<pi<<endl;}

Page 6: Strumienie wejścia/wyjścia

Programowanie C++ 6

Zmiana flag formatowaniamain (){ 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);

...

};

EA0xea234

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;}

EA0xEA234

Page 7: Strumienie wejścia/wyjścia

Programowanie C++ 7

main (){ char buffer[80]; cin.unsetf(ios::skipws); //czyści domyślneustawienie flagi cin>>buffer; cout<<"["<<buffer<<"]\n"; cin>>buffer; cout<<"["<<buffer<<"]\n"; 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 formatuclass ios {

public:

const long basefield = dec | oct | hex;

const long adjustfield = left | rigth | internal;

const long floatfield = scientific | fixed;

...

};

Hello, World.[ ][ Hello,][ World.]0XEA234

main (){ int n = 234; cout.setf(ios::hex | ios::uppercase| ios::showbase); cout<<n<<endl; cout.setf(ios::oct | ios::basefield); cout<<n<<endl;}

0XEA0352

Page 8: Strumienie wejścia/wyjścia

Programowanie C++ 8

Zmienne stanu klasy iosclass 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 = 022cin.rdstate = 0

cin.rdstate = 0^Zcin.rdstate = 3

Page 9: Strumienie wejścia/wyjścia

Programowanie C++ 9

Operatory dla stanu iosclass 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; }

40 90 20 ^Zsuma częściowa wynosi 15030 50 ^Zsuma całkowita wynosi 230

Page 10: Strumienie wejścia/wyjścia

Programowanie C++ 10

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 ( );

Page 11: Strumienie wejścia/wyjścia

Programowanie C++ 11

Nieformatowane wejściemain ()

{

char c;

while((c = cin.get() ) != EOF)

cout<<c;

cout<<endl;

}

main ()

{

char c;

while(cin.get (c) )

cout<<c;

cout<<endl;

}

Litwo! Ojczyzno mojaLitwo! Ojczyzno mojaTy jesteś jak zdrowie...Ty jesteś jak zdrowie...^Z

Litwo! Ojczyzno mojaLitwo! Ojczyzno mojaTy jesteś jak zdrowie...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 mojaLitwo! Ojczyzno mojaTy jesteś jak zdrowie...

Ty jesteś jak zdrowie

Page 12: Strumienie wejścia/wyjścia

Programowanie C++ 12

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 mojaLitwo! Ojczyzno mojaTy 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/2000Miesiąc = 1, Rok = 2000

Page 13: Strumienie wejścia/wyjścia

Programowanie C++ 13

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;

}

ABCDEFG65, 65, A, E, 69, 69YZEF

main ()

{

char buffer[] = "????????????????????";

cin.read(buffer, 8);

cout<<buffer<<" read: "<<cin.gcount( ) <<endl;

cin.read(buffer, 4);

cout<<buffer<<" read: "<<cin.gcount( ) <<endl;

}

ABCDEFGHIJKLMNABCDEFGH???????????? read: 8IJKLEFGH???????????? read: 4

Page 14: Strumienie wejścia/wyjścia

Programowanie C++ 14

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 );

Page 15: Strumienie wejścia/wyjścia

Programowanie C++ 15

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("1234567890", 4);

cout<<endl;

}

Litwo! Ojczyzno mojaLitwo! Ojczyzno mojaTy jesteś jak zdrowie...Ty jesteś jak zdrowie...^ZHelloABCDEF1234

Page 16: Strumienie wejścia/wyjścia

Programowanie C++ 16

Manipulatory strumieniNajbardziej popularne manipulatory strumieni:

Manipulator Strumień Działaniebinary ios ustawienie strumienia na tryb binarnydec ios konwersja dziesiętnaendl ostrem koniec linii i wyczyszczenie strumienia

wyjściowegoends ostrem koniec łańcucha wyjściaflush ostrem wyczyszczenie strumienia wyjściahex ios konwersja szesnastkowaoct ios konwersja ósemkowa

resetiosflags (long u) ios wyczyszczenie flag formatu określonych przez usetbase (int n) ostream konwersja do systemu o podstawie nsetfill (int ch) ostream znak wypełnienia ch

setiosflags (long u) ios ustawienie flag formatu określonych przez usetprecision (int n) ios ustawienie dokładności liczb

zmiennoprzecinkowych na nsetw (int n) ios ustawienie szerokości pola na n

ws istream pominięcie białych znakówtext ios ustawienie strumienia na tryb tekstowy

Page 17: Strumienie wejścia/wyjścia

Programowanie C++ 17

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 parametremios& 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;}

Page 18: Strumienie wejścia/wyjścia

Programowanie C++ 18

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:

Tryb otwarcia Znaczenieios::app Otwarcie pliku w trybie dołączania i ustawienie bieżącej

pozycji pliku na jego końcuios::ate Ustawienie bieżącej pozycji pliku na końcu

ios::binary Dane ze strumienia są traktowane jako binarneios::in Otwarcie do wejścia

ios::noncreate Nieistnienie pliku powoduje błąd operacji bez tworzenianowego pliku

ios::noreplace Istnienie pliku powoduje błąd operacjiios::out Otwarcie pliku do wyjścia

ios::trunc Likwidowanie istniejącej zawartości pliku

Page 19: Strumienie wejścia/wyjścia

Programowanie C++ 19

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)

Page 20: Strumienie wejścia/wyjścia

Programowanie C++ 20

Funkcje wirtualnemain (){ 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 funkcjijest odłożone do czasu realizacji programu i jest zależne od obiektu, na rzecz któregodana funkcja jest wywoływana.

Funkcja Write : 10 Styczeń 2000Funkcja Display : 10 1 2000Funkcja Display: 11 1 2000

class Date {...virtual Write (ostream& output = cout) const...};

Funkcja Write : 10 Styczeń 2000Funkcja Display : 10 Styczeń 2000Funkcja Display : 11 1 2000

Page 21: Strumienie wejścia/wyjścia

Programowanie C++ 21

PolimorfizmPolimorfizm - 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ą

Page 22: Strumienie wejścia/wyjścia

Programowanie C++ 22

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().X (). Y() : Y::q = 0x0d24. ~Y() ~X().X (). Y() : Y::q = 0x0d24. ~Y() ~X().

Page 23: Strumienie wejścia/wyjścia

Programowanie C++ 23

Czyste funkcje wirtualne i klasy abstrakcyjne

Media

Audio Book Periodical

CD Magazine Newspaper JournalTape Record

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; }};

Page 24: Strumienie wejścia/wyjścia

Programowanie C++ 24

Szablony funkcjiSzablon - 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); 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 = 33m = 33 n = 22d1 = 2000 1 17 d2 = 1999 9 9d1 = 1999 9 9 d2 = 2000 1 17

Page 25: Strumienie wejścia/wyjścia

Programowanie C++ 25

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; }

Page 26: Strumienie wejścia/wyjścia

Programowanie C++ 26

Szablon klasy stostemplate <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 132000 1 17

Page 27: Strumienie wejścia/wyjścia

Programowanie C++ 27

PojemnikiPojemnik 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;}};

Page 28: Strumienie wejścia/wyjścia

Programowanie C++ 28

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( );

Page 29: Strumienie wejścia/wyjścia

Programowanie C++ 29

Dziedziczenie szablonówDziedziczenie 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( ) = 31..3x[1] = 2.22x[2] = 3.33x[3] = 4.44

Page 30: Strumienie wejścia/wyjścia

Programowanie C++ 30

Szablony jako parametry szablonówPonieważ 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.21.0 1.1 1.2

Page 31: Strumienie wejścia/wyjścia

Programowanie C++ 31

Szablon klasy dla list jednokierunkowychListy - 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 T>class ListNode { friend class List<T>;protected: T data; ListNode* next;public: ListNode(T& t, ListNode<T>* p): data(t), next(p) { }};

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; }...

12

int

tdata 12

next p

ListNode< int >

Page 32: Strumienie wejścia/wyjścia

Programowanie C++ 32

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;}

Page 33: Strumienie wejścia/wyjścia

Programowanie C++ 33

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;}template <class T>void List <T>::print ( ){ for (ListNode<T>* p = first; p; p = p ->next) cout<<p -> data << "-> ”; cout<<”* \n”;}

#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; liczby.print( );}

Listy c.d.

3 -> 2 -> 1 -> 0 -> *Usunięto 22 -> 1 -> 0 -> *

data 2

next data 1

next

data 0

next

Page 34: Strumienie wejścia/wyjścia

Programowanie C++ 34

IteratoryIterator - 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;};

Page 35: Strumienie wejścia/wyjścia

Programowanie C++ 35

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

Page 36: Strumienie wejścia/wyjścia

Programowanie C++ 36

#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++; 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 <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; }}template <class T>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 ->*

Page 37: Strumienie wejścia/wyjścia

Programowanie C++ 37

Przyjaciel Listy

Lista może posiadać więcej niż jeden iterator:

Iteratory są od siebie niezależne.

// List.h

template <class T>class List { friend class ListIter<T>; //....};template <class T>class ListNode { friend class List<T>; friend class ListIter<T>;//....};

List<float> list; ListIter<float> 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;