180 likes | 352 Views
C++ Bjarne Stroustrup AT&T Bell-Laboratories. Historia 1980 - dodanie do C klas itp., jako punkt wyjścia przyjęto język Simula 67 (C z klasami) 1983/84 - powstanie C++ 1989 C++ wesja 2 (CFront 2.0, m.in. wielodziedziczenie) 1998 - Standard C++ (ISO/IEC 14882:1998).
E N D
C++Bjarne StroustrupAT&T Bell-Laboratories • Historia • 1980 - dodanie do C klas itp., jako punkt wyjścia przyjęto język Simula 67 (C z klasami) • 1983/84 - powstanie C++ • 1989 C++ wesja 2 (CFront 2.0, m.in. wielodziedziczenie) • 1998 - Standard C++ (ISO/IEC 14882:1998). • 2003 - tech. korekty (ISO/IEC 14882:2003) • Zalety • Bazuje na bardzo popularnym C • efektywność połączona z obiektowością • możliwość tworzenia dużych systemów ułatwiona przez obiektowość • duża przenaszalność • ciągły rozwój • Wady • połączenie mechanizmów niskopoziomowych (z C) z wysokopoziomowymi mechanizmami obiektowymi - w C++ trudno programować dobrze • C++ zawiera prawie wszystkie znane mechanizmy obiektowe, a także połączenie tych mechanizmów z innymi, np. przeciążaniem funkcji
Literatura • Język C++; Bjarne Stroustrup; WNT 2000; wyd. 5te i zmienione, • Język C++, ćwiczenia i rozwiązania; David Vandevoorde; WNT 2001, • The C++ Standard: Incorporating Technical Corrigendum No. 1, British Standards Institute782 pages, 2nd ed.,19 December 2003, • Podstawy języka C++; Stanley B. Lippman, Josee Lajoie; WNT 2001, • Podstawy języka C++, ćwiczenia i rozwiązania; Clovis L. Tondo; WNT 2001, • C++ Biblioteka standardowa, podręcznik programisty; Nicolai M. Josuttis; Helion 2003, • Projektowanie i rozwój języka C++, Bjarne Stroustrup, WNT 1996, • C++ zadania i odpowiedzi, Tony L. Hansen, WNT 1994, • Internet (draft proposed International Standard for Information Systems – Programming language C++, X3J16/96-0225, 2 XII 1996; 699 stron w tym 370 język, 329 biblioteki).
Komentarze • /* wielowierszowy */ • // jednowierszowy • Deklaracje zmiennych • int x; // zmienna x typu integer • int y = 3; // zmienna y z określoną wartością początkową 3 • int z = y; // zmienna z określoną wartością pocz. y (czyli 3) • char * p; // zmienna p typu wskaźnik do znaku • T y; // zmienna y typu T • // T może być typem pierwotnym, klasą, strukturą • // lub unią • float tab [100]; // 100-elementowa tablica liczb rzeczywistych • int* tablica; // zapewne tablica liczb całkowitych • // rozmiar zostanie określony przez new • char ** str; // zapewne tablica wskaźników do znaków (czyli // napisów), rozmiar zostanie określony przez new • int (*arr) [10]; // wskaźnik do 10-elementowej tablicy liczb • int p[ ] = {4, 7, 8}; // 3-elementowa tablica zawierająca liczby 4, 7, 8 • Uwaga: nazwa tablicy jest utożsamiana ze stałym wskaźnikiem do pierwszego elementu tablicy. Elementy tablicy są zawsze indeksowane od 0. • int tab1 [100 ];jestprawie równoważneint * tab2; • tab1 [10 ] = 123; *(tab2 + 10) = 123; • *(tab1 + 10) = 123;tab2 [10 ] = 123; • a nawet • 10[tab1] = 123; 10[tab1] = 123; • ALE tab1 jest zainicjowane a tab2 NIE i po lewej jest 100-elementowa tablica, a po prawej nie ma jeszcze żadnej tablicy!!!
Stałe (tylko C++) • const int x = 145; // nie można zmienić wartości x • const int *p; // nie można zmien. liczb wsk. przez p • const int V[ ] = {1, 2, 3, 4}; // nie można zmienić eltów tablicy V • const char * napis = “abcdef’; • char * const nap = “abcdef”; • const char* const nap3 = "abcdef"; • Specyfikacja const stwierdza, że nie można zmienić obiektu w ten • sposób zadeklarowanego. • V [ 3 ] = 10; // nielegalne • V = new int; // ok • napis [ 3 ] = ‘0’; // nielegalne • napis = “xyz”; // ok • nap [ 3 ] = ‘0’; // ok • nap = “xyz”; // nielegalne • Często używa się deklaracji const dla parametru funkcji aby podkreślić, • że funkcja tego parametru nie może zmienić (read only). • char * strcpy (char * p, const char * q); // *q nie może być zmieniane • Typy • (Niektóre) typy pierwotne: • char, short, int, long, float, double • Typy wyprowadzane (derived types): • * wskaźnik • & referencja • [ ] tablica • ( ) funkcja • Typy wyliczeniowe: • enum kolor { czerowny, bialy, czarny, zielony }; • // wprowadza już nazwę typu - kolor
Konwersja typów: (stare) (char *) w float (29) (nowe) static_cast<float>(3) typ void “pusty“ typ • Wyrażenia • Instrukcja przypisania jest wyrażeniem (z efektami ubocznymi). • x = 23; • x++ wartością wyrażenia jest x • po wykonaniu wyrażenia x ma wartość zwiększoną o 1 • ++x wartością wyrażenia jest x+1 • po wykonaniu wyrażenia x ma wartość zwiększoną o 1 • x----x podobnie • x += w; // x = x + w; • Zamiast + może wystąpić inny operator, np. *, - • && koniunkcja || alternatywa • ! negacja • == porównanie != różne • int *p; int x; • *p obiekt wskazywany przez p • &x adres obiektu x; użycie: p = &x; • Uwaga na wskaźniki: • char *p = new char[strlen(src+1)]; • strcpy(src, p); • // Błędny fragment programu (ale kompilujący się bez • // ostrzeżeń) zwn złe położenie czerwonego nawiasu.
Referencje • T - typ, T& - typ “referencja do T” • Referencja jest inną nazwą obiektu (aliasem). • int i = 1; • int& r = i; // wartością i oraz r jest ten sam obiekt (liczba) • // zmienna typu referencyjnego musi być zainicjowana • r = 5; // teraz także i == 5 • Referencje są używane przy parametrach funkcji do przekazywania • parametrów przez referencję (tak, jak przez zmienną w Pascalu). • Nie może być wskaźników do referencji (ani tablic referencji). Ale referencja do wskaźnika jest poprawna. • Referencja to nie jest wskaźnik !!! • Przykład: • Funkcja zamieniająca wartości dwóch zmiennych. • (1) za pomocą wskaźników • void swap (int * a, int * b) • { • int temp; • temp = *a; *a = *b; *b = temp; • } • wywołanie: swap (&x, &y ); // tu & oznacza adres • (2) za pomocą referencji • swap (int& a, int& b) // parametrem aktualnym musi być zmienna • { • int temp; • temp = a; a = b; b = temp; • } • wywołanie: swap (x, y); • Referencji używamy najczęściej wtedy, gdy jako parametr funkcji • chcemy przekazać obiekt, a nie jego kopię.
Instrukcje • Wyrażenie zakończone ; jest instrukcją. np. x++; • { lista instrukcji } • if (wyrażenie) instrukcja • if (wyrażenie) instrukcja1 else instrukcja2 • if (x < 0) • x++; • while (wyrażenie) instrukcja • do instrukcja while (wyrażenie); • while (i < n && tab [ i ] != x) // n - rozmiar tablicy • i++; • do x = x - y; while (x > y); • { char *nap1 = ‘123456789’; • char nap2 [100] ; • char * p, * q; • p = nap1; q = nap2; • while ( *p != 0) * q ++ = *p ++; • } • for (instr_start wyr_końcowe; wyr) instrukcja2; • instr_start; • while (wyr_końcowe) • { • instrukcja2; • wyr; • } • for (i=0; i < n ; i++) tab [ i ] = 100;
break; // przerywa wykonanie pętli lub instrukcji switch • return wyrażenie; // powrót z funkcji • switch (wyr) • { • case const1: instr1; • instr2; • ..... • break; // powoduje wyjście z instrukcji switch • case const2: instr1; • ...... • default: instr1; • instr2; • .... • } • Funkcje • float pow (float x, int n) • { • float y = 0; • if (n < 0) • error (“ ujemny wykładnik”); • else • switch ( n ) • { • case 0: y = 1; break; • case 1: y = x; break; • dafault: y = x * pow ( x, n-1 ); • } • return(y); • }
void main ( ) • { • ...... // główna funkcja • } • Przekazywanie parametrów • przez wartość tylko (normalny sposób w C) ALE • może być typ referencyjny (tylko C++) • void zamien (int &x, int &y) • // zamienia wartości zmiennych x i y; • { • int pom; • pom = x; • x = y; • y = pom; • } • void main ( ) • { • int a = 13; • int b = 3445; • zamien (a, b); • ... • }
Deklaracja funkcji: określa jej nagłówek (nazwę, typ, liczbę i typy • argumentów) • int zamien (int &x, int &y); • Definicja funkcji: definiuje treść funkcji • int zamien (int &x, int &y) • { .... } • Każda funkcja musi być zadeklarowana przed użyciem. • Argumenty domyślne (tylko C++) • void f (int i, float x = 1.0); // argumenty domyślne muszą • być na końcu • możliwe wywołania: • f (2, 3.0); • f ( 5); • Argument domyślny jest obliczany w momencie wywołania funkcji. • Funkcje wstawiane (inline) (tylko C++) • inline int max (int x, int y) • { • return x > y ? x : y; • } • Przeciążanie funkcji (tylko C++) • Deklaracja kilku funkcji o tej samej nazwie, lecz o różnej liczbie lub • różnych typach argumentów. • void print (char * s); // będzie wykonana dla wywołania print (“aaa”) • void print (int n); // będzie wykonana dla wywołania print (10)
Typy - c.d. (w C++) • Struktury i unie • struct para { • char * nazwa; • int wartość; • }; • para p, kolor k; • struct entry { • char * nazwa; • char typ; // ‘n’ - dla napisu, ‘l’ - dla liczby • union { • char * wartość_napis; // używana, gdy typ == ‘n’ • int wartość_liczba; // używana, gdy typ == ‘l’ • }; • entry en; • ... • if (en.typ == ‘n’) • cout << en.wartość_napis • else • cout << en.wartość.liczba; • Tworzenie i niszczenie obiektów • char * s = new char [10]; // napis 9-cio znakowy • int * wsk = new int; • wsk = new int; // wskaźnik do nowego obiektu - liczby • delete wsk; // zwalnia pamięć wskazywaną przez wsk • delete[] s; // zwalnia 10-cio elementową tablicę s
Wejście/wyjście (strumienie) • (tylko C++) • operatory << >> • wynikiem zastosowania tych operatorów jest strumień. • standardowe strumienie cin, cout, cerr • cout << “Podaj wartości dla i oraz j: “; • cin >> i >> j; • cout << “Sumą i oraz j jest “ << i + j << “\n”; • Są też funkcje: • get(c) f.get(c) • put (c) f.put (c) • eof () f.eof () • cout, cin, f - to są obiekty klasy iostream. • Klasa fstream obsługuje pliki dyskowe (jest podklasą klasy iostream). • Obiekty klas ifstream i ofstream są plikami otwieranymi domyślnie do czytania i pisania. • ifstream input (“dane.txt”); // tworzy strumień związany • // z plikiem “dane.txt” • // otwartym do czytania • ofstream output (“wynik.txt”); // do pisania
Struktura programu i widoczność nazw • Program jest ciągiem deklaracji typów, stałych, zmiennych i • funkcji. • Program może być wieloplikowy. Plik pełni rolę czegoś • w rodzaju modułu (grupuje deklaracje typów, zmiennych i funkcji • na nich działających). • Nie ma zagnieżdżania funkcji. • Wykonanie programu zaczyna się od wykonania funkcji main. • Wszystkie typy i funkcje są nazwami zewnętrznymi. • Nazwy globalne: zadeklarowane na poziomie pliku. • Każda nazwa globalna jest widoczna od momentu jej • zadeklarowania do końca pliku. • Nazwa zmiennej lokalnej w funkcji jest widoczna od momentu jej • zadeklarowania do końca funkcji. • Nazwa zmiennej lokalnej w bloku jest widoczna od momentu jej • zadeklarowania do końca bloku. • Deklaracja funkcji: • int f (int x); // tylko nagłówek • extern char * g ( ); // • Definicja funkcji: • int f (int x) • { • ...... // treść funkcji • } • Plik nagłówkowy: zawiera deklaracje, które mają być wspólne dla • wielu plików. • #include <fstream> // włączenie standardowego pliku nagłówkowego • #include "mojplik.h" // włączenie własnego pliku nagłówkowego
Liczymy liczbę wystąpień słów kluczowych na pliku • #include <fstream> • char *słowa [ ] = • { “begin”, “end”, “if”, “while”, “record” }; • const n = 5; • int licznik [ n ]; • char * daj_słowo ( ifstream str); // deklaracja funkcji • // daje następne słowo ze strumienia; NULL - jeśli nie ma już słowa • void wypisz_wynik ( ) • // wypisuje wynik - słowa i liczbę wystąpień • { • for ( int i = 0; i < n; i++) • cout << słowa [ i ] << “\t” << licznik [ i ] << “\n”; • } • void policz (char * slowo ) • // dla danego słowa zwiększa licznik o 1 jeśli jest to sł. kluczowe • { • int i = 0; • while ( i < n && strcmp (slowo, slowa [ i ]) != 0) i++; • if ( i < n ) • licznik [ i ] ++; • } • void main ( ) • { • char * s; • fstream str (“ ... “); // .związanie strumienia str z plikiem • while ((s = daj_slowo( str )) != NULL) • policz (s ); • wypisz_wynik (); • }
Liczymy, ile jest różnych słów na pliku. Przez słowo rozumiemy ciąg znaków nie zawierających “białych” znaków. W wyniku wypisujemy słowa i liczbę ich wystapień w kolejności alfabetycznej. Plik o nazwie czyt.h #include <fstream> // funkcja czyta słowo (ciąg znaków różnych "białych" znaków extern char * daj_slowo (ifstream & f); Plik o nazwie tree.h // typy danych określające strukturę do przechowywania słów #include <fstream> struct wezel { char * slowo; int ile; wezel* lewy; // wskaźnik do lewego poddrzewa wezel* prawy; // wskaźnik do prawego poddrzewa }; typedef wezel* drzewo; extern void wstaw(char * s, drzewo & D); // wstawia słowo do drzewa extern void wypisz(drzewo D, ofstream & wy); // obchodzi drzewo Plik o nazwie slowa.h #include <fstream> // <> dla bibliotek standardowych #include "tree.h" // " " dla bibliotek prywatnych extern void pisz_wyniki( ofstream & wynik); // wypisuje wynik extern void licz (ifstream & dane); // czyta i liczy słowa
Plik zawierający treść funkcji czytającej słowo #include <fstream.h> #include <string.h> #include "czyt.h" static const MAX = 50; // maksymalna długość słowa static char buf[MAX]; // bufor do przechowywania słowa static inline int BIALE (char c) { return (c == ' ' || c == '\t' || c == '\n'); } // funkcja zwraca wskaźnik do przeczytanego słowa lub NULL, // jeśli słowa już nie było char * daj_slowo (istream & f) { int i; char c; char * s; c = ‘ ‘; while (!f.get(c).eof() && BIALE (c)); // pomijanie spacji if (BIALE (c) || f.eof () ) return(NULL); // nie ma kolejnego slowa // czytaj słowo do bufora i = 0; do buf [i++] = c; while ( !f.get(c).eof () && (! BIALE (c)) && (i < MAX-1)); // zwracamy przeczytane słowo buf[i] = '\0'; s = new char [i+1]; strcpy (s, buf); return(s); }
Plik zawierający operacje na drzewie BST • #include <fstream.h> • #include "tree.h" • // funkcja wstawia słowo s do drzewa D, zwiększa licznik • void wstaw(char * s, drzewo & D) // parametr przekazany przez ref. • { • int b; • if (D == NULL) { // nie bylo jeszcze tego słowa • D = new wezel; D -> slowo = s; D -> ile = 1; • D -> lewy = D -> prawy = NULL; • } • else { • b = strcmp (D -> slowo, s); • if (b > 0) // idziemy w lewo • wstaw(s, D -> lewy); • else if (b < 0) // idziemy w prawo • wstaw(s, D -> prawy); • else • { • (D -> ile)++; • return; • } • } • } // koniec funkcji • // wypisanie słów z drzewa D na plik wy • void wypisz(drzewo D, ofstream & wy) • { • if (D == NULL) return; • wypisz (D -> lewy, wy); • wy << D -> slowo << " " << D ->ile << "\n"; • wypisz (D -> prawy, wy); • }
Plik zawierający treści funkcji liczących liczbę słów #include <fstream> #include "czyt.h" #include "tree.h" #include “slowa.h” static drzewo Slowa = NULL; // drzewo slow // funkcja wypisuje częstości wystśpień słów w porządku alfabetycznym // na plik wy void pisz_wyniki( ofstream & wynik) { wypisz(Slowa, wynik); } // funkcja liczy częstotliwość występowania słów na pliku we */ void licz (ifstream & dane) { char * s; while ((s = daj_slowo(dane)) != NULL) wstaw (s, Slowa); } • Program główny • #include <fstream> • #include “slowa.h” • void main ( int argc, char * argv [ ] ) • { // utworzenie obiektów dane i wynik • ifstream dane (argv [1]); • ofstream wynik (argv[2]); • licz (dane ) ; pisz_wyniki (wynik); • }