C++ Bjarne Stroustrup AT&T Bell

Download Report

Transcript C++ Bjarne Stroustrup AT&T Bell

OOP
C++ - wstêp w zakresie C 1
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).
– 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
OOP
C++ - wstêp w zakresie C 2
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 Institute
816 pages, 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).
OOP
C++ - wstêp w zakresie C 3
Komentarze
/* wielowierszowy */
// jednowierszowy
Deklaracje zmiennych
int x;
int y = 3;
int z = y;
char * p;
T y;
// zmienna x typu integer
// zmienna y z określoną wartością początkową 3
// zmienna z określoną wartością pocz. y (czyli 3)
// zmienna p typu wskaźnik do znaku
// zmienna y typu T
// T może być typem pierwotnym, klasą, strukturą
// lub unią
float tab [100];
int* tablica;
// 100-elementowa tablica liczb rzeczywistych
// 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 ];
jest prawie równoważne
tab1 [10 ] = 123;
*(tab1 + 10) = 123;
a nawet
10[tab1] = 123;
ALE tab1 jest zainicjowane a tab2 NIE !!!
int * tab2;
*(tab2 + 10) = 123;
tab2 [10 ] = 123;
10[tab1] = 123;
OOP
C++ - wstêp w zakresie C 4
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
OOP
C++ - wstêp w zakresie C 5
Konwersja typów:
(stare)
(char *) w
float (29)
(nowe)
static_cast<float>(3)
“pusty“ typ
typ void
Wyrażenia
Instrukcja przypisania jest wyrażeniem (z efektami ubocznymi).
x = 23;
x++
++x
x--
wartością wyrażenia jest x
po wykonaniu wyrażenia x ma wartość zwiększoną o 1
wartością wyrażenia jest x+1
po wykonaniu wyrażenia x ma wartość zwiększoną o 1
--x
podobnie
x += w;
// x = x + w;
Zamiast + może wystąpić inny operator, np. *, &&
!
==
koniunkcja
negacja
porównanie
int *p; int x;
*p
obiekt wskazywany przez p
&x
adres obiektu x; użycie:
||
alternatywa
!=
różne
p = &x;
OOP
C++ - wstêp w zakresie C 6
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ę.
OOP
C++ - wstêp w zakresie C 7
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)
i++;
// n - rozmiar tablicy
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;
OOP
C++ - wstêp w zakresie C 8
break;
return wyrażenie;
// przerywa wykonanie pętli lub instrukcji switch
// powrót z funkcji
switch (wyr)
{
case const1: instr1;
instr2;
.....
break;
case const2: instr1;
......
default:
instr1;
instr2;
....
}
// powoduje wyjście z instrukcji switch
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);
}
OOP
C++ - wstêp w zakresie C 9
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);
...
}
OOP
C++ - wstêp w zakresie C 10
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)
OOP
C++ - wstêp w zakresie C 11
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];
int * wsk = new int;
// napis 9-cio znakowy
wsk = new int;
// wskaźnik do nowego obiektu - liczby
delete wsk;
delete[] s;
// zwalnia pamięć wskazywaną przez wsk
// zwalnia 10-cio elementową tablicę s
OOP
C++ - wstêp w zakresie C 12
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)
put (c)
eof ()
f.get(c)
f.put (c)
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
OOP
C++ - wstêp w zakresie C 13
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);
extern char * g ( );
// tylko nagłówek
//
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
OOP
C++ - wstêp w zakresie C 14
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 ();
}
OOP
C++ - wstêp w zakresie C 15
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
OOP
C++ - wstêp w zakresie C 16
Plik zawierający treść funkcji czytającej słowo
#include <fstream.h>
#include <string.h>
#include "czyt.h"
static const MAX = 50;
static char buf[MAX];
// maksymalna długość słowa
// 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);
}
OOP
C++ - wstêp w zakresie C 17
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);
}
OOP
C++ - wstêp w zakresie C 18
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);
}