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
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
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
...
};
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
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;}
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
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
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
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
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 ( );
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
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
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
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 );
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
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
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;}
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
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)
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
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ą
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().
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; }};
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
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; }
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
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;}};
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( );
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
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
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 >
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;}
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
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;};
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++)...
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 ->*
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;