C++
C++ to obiektowo zorientowany język programowania. Został on zaprojektowany przez B.Stroustrupa z myślą o programowaniu systemowym oraz do zaawansowanych obliczeń matematycznych. Świadome używanie C++ do rozwiązywania problemów algorytmicznych daje dużo satysfakcji doświadczonym programistom, zwłaszcza dlatego że generowany przez kompilator kod jest bardzo efektywny.
Celem kursu jest zapoznanie studentów z bogatą składnią języka C++, najważniejszymi technikami stosowanymi w programowaniu z wykorzystaniem tego języka oraz z obszernymi fragmentami biblioteki standardowej STL.
wymagane przygotowanie
- Umiejętność programowania strukturalnego w języku ANSI C.
- Znajomość podstawowych struktur danych (tablice, listy, drzewa, grafy).
literatura
Literatura papierowa:
- B.Stroustrup: Język C++. WNT, Warszawa 2000.
- S.B.Lippman, J.Lajoie: Podstawy języka C++. WNT, Warszawa 2001.
- C.L.Tondo, B.P.Leung: Podstawy języka C++. Ćwiczenia i rozwiązania. WNT, Warszawa 2001.
- J.Grębosz: Symfonia C++ (tom 1, 2, 3). Oficyna Kallimach, Kraków 2002.
- J.Grębosz: Pasja C++ (tom 1, 2). Oficyna Kallimach, Kraków 2003.
- N.M.Josuttis: C++. Biblioteka standardowa. Podręcznik programisty. Wydawnictwo Helion, Gliwice 2003.
Literatura elektroniczna:
Terminarz
- wykład: czwartek 10-12 s.140 (P.Rzechonek)
-
laboratorium:
wtorek 12-14 s.107 (T.Cichocki)
czwartek 12-14 s.110 (P.Rzechonek)
Ogłoszenia
- 12.05.2008
-
Laureatami w konkursie na najskuteczniejszego programistę C++ zostali:
Kamil Graczyk, Marcin Sas-Szymański i Tomasz Wasilczyk.
Spośród tego grona wyłoniłem zwycięzcę - został nim Marcin Sas-Szymański! Laureatom a w szczególności zwyciężcy pragnę serdecznie pogratulować :) a wszystkim przybyłym uczestnikom konkursu podziękować za udział w spotkaniu. PRz. - 29.05.2008
- Postanowiłem zorganizować konkurs :) na najskuteczniejszego programistę C++. Kandydatów (minimum 3 osoby) wyznaczę na podstawie punktów zgromadzonych w czasie semestru i spośród nich arbitralnie wybiorę ostatecznego zwycięzcę. Przewidziane są drobne nagrody (raczej nie będzie to VW Passat z GPS)! Termin rozstrzygnięcia konkursu: 12 czerwca o godzinie 12:15 w sali 141 - zapraszam wszystkich uczestników kursu.
- 29.05.2008
- Zadanie 11 i 12 będę odbierał w mojej grupie 5 czerwca.
- 27.05.2008
- W dniach 10 i 12 czerwca nie odbędą się zajęcia z C++ z powodu odbywających się w naszym instytucie zajęć dla licealistów (mogą to być nasi przyszli studenci :).
- 9.05.2008
- Zadanie 9 będę odbierał w mojej grupie 15 maja w godzinach 12-14. Kto nie będzie mógł przyjść na te dodatkowe zajęcia, powinien dostarczyć program 9 dwa tygodnie póżniej, czyli 29 maja.
- 11.03.2008
- Postaram się zamieszczać listy z zadaniami w czwartek lub w piątek, chociaż nie zawsze będzie to możliwe. Na szczęście obecne zadania nie są ani trudne ani czasochłonne :)
- 1.03.2008
- W tym miejscu będą się pojawiać ogłoszenia organizacyjne dotyczące wszystkich studentów uczestniczących w kursie.
Laboratorium
zasady zaliczenia przedmiotu
- ogólnie:
- W semestrze będzie opublikowanych (na tej stronie) kilkanaście prostych zadań do zaprogramowania. Za każde poprawnie zaprogramowane zadanie i oddane w terminie można będzie dostać 10 punktów albo 5 punktów za zadanie oddane z tygodniowym opóźnieniem.
- terminy:
- Zadania do zaprogramowania będą ogłaszane w tygodniu poprzedzającym termin ich realizacji. Zadania należy oddawać w wyznaczonym terminie. Spóźnienia dłuższe niż tydzień nie będą tolerowane, za wyjątkiem uzasadnionych sytuacji: choroba potwierdzona zwolnieniem lekarskim, wezwanie na policję lub do sądu, itp.
- prezentacje:
- Programy należy prezentować osobiście w czasie pracowni (proszę nie wysyłać programów pocztą elektroniczną, ani nie przekazywać ich poprzez kolegów czy koleżanki). W trakcie prezentacji programu trzeba się liczyć z pytamiami dotyczącymi zadania: metoda rozwiązania, zastosowane konstrukcje językowe, wykorzystane technologie, itp.
- oceny:
- Aby zaliczyć laboratorium na ocenę dostateczną trzeba do końca semestru zdobyć 50% z wszystkich możliwych do uzyskania punktów; na ocenę bardzo dobra trzba będzie zgromadzić 90% punktów; oceny pośrednie pozostją w liniowej zależności od przedstawionych wymagań granicznych.
listy zadań
- 4/6.03.2008: liczby naturalne w zapisie słownym (ps/pdf)
- 11/13.03.2008: schowek na liczbę (ps/pdf)
- 18/20.03.2008: daty w kalendarzu gregoriańskim (ps/pdf)
- 1/3.04.2008: tablica bitów (ps/pdf)
- 8/10.04.2008: rozkład liczb naturalnych na czynniki pierwsze (ps/pdf)
- 15/17.04.2008: konwersja łańcuchów znakowych na liczby (ps/pdf)
- 22/24.04.2008: kalkulator ONP (ps/pdf)
- 29.04/8.05.2008: uniqueleton (ps/pdf)
- 13/15.05.2008: długie liczby całkowite (ps/pdf)
- 20/29.05.2008: sortowanie za pomocą obiektów funkcyjnych (ps/pdf)
- 27/29.05.2008: stos i kolejka (ps/pdf)
- 3/5.06.2008: bezpieczne pliki i manipulatory (ps/pdf)
- zadanie dodatkowe (tylko dla tych studentów, którym brakuje niewielu
punktów do zaliczenia przedmiotu)
17/19.06.2008: automaty skończone (ps/pdf)
rankingi
Wykład
- 28.02.2008 (wstęp do C++):
- Podstawowe cechy obiektowego programowania w C++.
- Referencje; przekazywanie parametrów do funkcji poprzez referancje.
- Definicja klasy; deklarowanie obiektów danej klasy.
- Odwołania do składowych w obiekcie.
- Pola i metody w klasie; definiowanie metod poza klasą.
- Konstruktory i destruktory.
- Standardowe wejście i wyjście (cin, cout, clog, cerr).
- Podstawowe manipulatory.
- Łańcuchy znakowe (string); dodawanie jako operator konkatenacji.
- 6.03.2008 (klasy i obiekty, stałe pola, lista inicjalizacyjna):
- Stałe (modyfikator const); stałe parametry funkcji; stałe pola.
- Wskaźniki do stałych i stałe wskaźniki.
- Referencje do stałych obiektów jako argumenty funkcji.
- Deklarowanie stałych obiektów.
- Usuwanie stałości (atrybut mutable).
- Tworzenie (operator new) i usuwanie (operator delete) obiektów ze sterty.
- Wskaźnik this.
- Przeciążanie metod i konstruktorów
- Konstruktor domyślny (bezargumentowy) i kopiujący.
- Lista inicjalizacyjna.
- Tablice obiektów.
- 13.03.2008 (metody wbudowane, przeciążanie metod, składowe statyczne):
- Funkcje i metody wbudowane (atrybut inline).
- Przeciążanie funkcji, metod i konstruktorów.
- Parametry domyślne.
- Składowe statyczne (atrybut static).
- Wyjątki - wstęp.
- Strumienie napisowe (strumień ostringstream oraz istringstream).
- 20.03.2008 (przeciążanie operatorów, przyjaźń):
- Funkcje i metody zaprzyjaźnione (atrybut friend).
- Przeciążanie operatorów dla typów zdefiniowanych przez użytkownika.
- Operatory składowe i zaprzyjaźnione funkcje operatorowe.
- Operatory których nie można przeciążać (operator zakresu (::), operator dostępu do składowych (. i .*), operator warunkowy ?:), operator rozmiaru danych (sizeof) i operatory rzutowania).
- Operatory predefiniowane (przypisanie (=), uzyskanie adresu (&), sekwencja obliczeń (,) oraz tworzenie i usuwanie obiektów w pamięci (new, new[], delete i delete[]).
- Jednoargumentowe operatory pre- i post- inkrementacji/dekrementacji (++ i --).
- Składowy niestatyczny operator przypisania (=).
- Składowy niestatyczny operator indeksowania ([]).
- Składowy niestatyczny operator wywołania funkcji (()).
- Składowy niestatyczny operator dostępu do składowych (->).
- Statyczne operatory zarządzania pamięcią wolną (new, new[], delete i delete[]).
- Zaprzyjaźnione operatory czytania ze strumienia (>>) i pisania do strumienia (<<).
- 27.03.2008 (dziedziczenie):
- Istota dziedziczenia: projektowanie hierarchii klas, dostosowanie gotowej klasy do własnych potrzeb.
- Definiowanie dziedziczenia: klasa bazowa i pochodna.
- Zakresy widzialności składowych i dostęp do składników klasy bazowej w klasie pochodnej.
- Dziedziczenie publiczne i niepubliczne; wybiórcze udostępnianie za pomocą deklaracji using.
- Nie dziedziczy się: składowych prywatnych, konstruktorów, destruktora, przypisania kopiującego.
- Inicjalizacja i destrukcja obiektów w warunkach dziedziczenia.
- Wskaźnikiem do klasy bazowej można pokazywać na obiekty klas pochodnych.
- Dziedziczenie wielobazowe.
- Dziedziczenie wirtualne.
- 3.04.2008 (polimorfizm i rzutowanie):
- Hierarchia klas i niejawne rzutowanie w górę wskaźników i referencji do obiektów.
- Definiowanie metod wirtualnych.
- Działanie polimorfizmu w przypadku dziedziczenia.
- Wczesne i późne wiązanie.
- Destruktory w klasach polimorficznych.
- Klasy abstarkcyjne i metody czysto wirtualne.
- Jawne rzutowanie w górę wskaźników i referencji do obiektów w hierarchii klas za pomoca operatora dynamic_cast na etapie wykonania.
- Jawne rzutowanie na etapie kompilacji za pomoca operatorów static_cast i reinterpret_cast.
- Składowy operator rzutowania w klasie.
- Konstruktor konwertujący bez atrybutu explicit.
- RTTI - identyfikacja dowolnych typów na etapie wykonania.
- 10.04.2008 (wyjątki):
- Zgłaszanie wyjątków (instrukcja throw) i ich wyłapywanie (instrukcja try-catch).
- Dopasowywanie wyjątków w blokach catch.
- Mechanizm lotu wyjątku (zwijanie stosu).
- Specyfikacja wyjątków w funkcjach i w metodach polimorficznych.
- Wyjątki zgłaszane w kontruktorach.
- W destruktorach nie wolno zgłaszać wyjątków.
- Zdobywanie zasobów poprzez inicjalizację.
- Klasa auto_ptr.
- Wyjątki standardowe i ich hierarchia w STL.
- Definiowanie własnych wyjątków.
- 17.04.2008 (szablony funkcji):
- 24.04.2008 (szablony klas):
- 8.05.2008 (strumienie):
- Standardowe strumienie wejścia/wyjścia cin, cout, clog i cerr.
- Hierarchia klas strumieni.
- Operatory << i >> do formatowanego wstawiania i wyjmowania ze strumienia.
- Flagi stanu formatowania w strumieniach.
- Nieformatowane operacje wejścia/wyjścia.
- Manipulatory standardowe; definiowanie własnych manipulatorów.
- 29.05.2007 (strumienie):
- Obsługa błędów w strumieniach.
- Strumienie związane z plikami ifstream i ofstream.
- Strumienie związane z łańcuchami znakowymi istringstream i ostringstream.
- Łączenie strumieni.
- Współpraca ze starą biblioteką cstdio.
- 5.06.2007 (kontenery i iteratory):
- Kontenery STL implementują semantykę wartości.
- Brak bezpieczeństwa w kontenerach.
- Cechy elementów pamiętanych w kontenerach.
- Wspólne operacje kontenerów. Leksykograficzne porównywanie kontenerów.
- Kontenery sekwencyjne (vactor, deque, list) i asoscjacyjne (set, multiset, map, multimap).
- Kontenery specjalne: stack, queue priority_queue.
- Iteratory STL implementują semantykę wskaźnika na element w tablicy.
- Operatory w iteratorach.
Notatki
Wprowadzenie do C++
Pierwsze programy
Najprostszy program w języku C++ wygląda następująco:
Każdy program w języku C++ musi mieć zdefiniowana funkcję main().
Wykonanie programu rozpoczyna się od wywołania tej właśnie funkcji.
Funkcja main() zwraca wartość typu int, która jest
przekazywana do systemu operacyjnego.
Jeśli jawnie nie zwróci się żadnej wartości w tej funkcji, to domyślnie
funkcja main() zwróci wartość 0.
Wartość zerowa oznacza poprawne zakończenie się programu a wartość niezerowa
sygnalizyje jakiś błąd.
Następny program wypisze na standardowy wyjściu komunikat powitalny:
Pliki nagłówkowe zawierające deklaracje funkcji i zmiennych globalnych oraz
definicje klas z biblioteki standardowej nie mają rozszerzenia
.h.
Dyrektywa #include<iostream> dołącza plik nagłówkowy,
zawierający definicję podstawowych mechanizmów strumieniowych i deklarację
obiektów związanych ze standardowym wejściem i wyjściem.
Dyrektywa użycia using namespace std; odnosząca się do
standardowej przestrzeni nazw std jest włączona po to, by nazw
zdefiniowanych w bibliotece standardowej nie trzeba było kwalifikować za
pomocą operatora zakresu 9::).
Jawne wskazywanie przestrzeni nazw, w których zdefiniowane są obiekty
zmniejsza bowiem czytelność kodu, na przykład std::cin zamiast
samego cin.
W bibliotece standardowej przeciążono operatory przesunięć bitowych
(<< i >>) w odniesieniu do operacji
na strumieniach.
Operatory te sugerują kierunek przepływu danych.
Można ich używać kaskadowo, czyli w jednym wyrażeniu można wilokrotnie
zapisać dane do strumienia wyjściowego operatotem << albo
wielokrotnie odczytać dane ze strumienia wejściowego operatotem
>>.
Wynikiem działania operatorów przesunięć bitowych na strumieniach jest
pierwszy argument, czyli referencja do strumienia.
Operatory przesunięć bitowych są lewostronnie łączne, więc przykładowe
wyrażenie cout<<"wartość x="<<x<<endl należy
zinterpretować ((cout<<"wartość x=")<<x)<<endl.
Kolejny program najpierw wczyta ze standardowego wejścia liczbę całkowitą
int a potem wypisze na standardowy wyjściu informację o znaku
tej liczby:
Strumienie związane ze standardowym wejściem i wyjściem, czyli
cin, cout, clog i cerr,
są strumieniami, które automatycznie dokonują konwersji danych z postaci
binarnej na tekstową i odwrotnie.
W ostatnim przykładzie pokazano, jak można zareagować na błędne dane
w strumieniu wejściowym.
Wykorzystano do tego celu przeciążony dla strumieni operator rzutowania
(bool) w połączeniu z operatorem nagacji logicznej
(!).
Po nieudanym zapisie albo odczycie strumień przechodzi do stanu z błędem,
co można wykryć testując go jak w przykładowym programie if
(!cin).
Kompilowanie programów
Programy napisane w C++ i różne konstrukcje językowe prezentowane na tej stronie są kompilowane kompilatorem g++ w wersji 4.1.2 pod kontrolą systemu operacyjnego Linux Ubuntu 7.04.
Załóżmy, że napisaliśmy program w C++ i zapisaliśmy go w pliku o nazwie
program.cpp.
Aby go skompilować, należy wydać następujące polecenie:
Jeśli w programie nie było żadnych błędów, to w wyniu otrzymamy program
wykonywalny o nazwie a.out.
Jeśli chcemy nadać inną nazwę programowi wykonywalnemu, to trzeba użyć opcji
kompilatora -o:
Po takim wywołaniu kompilator utworzy plik z programem wykonywalnym o nazwie
prog.exe.
Kompilowanie programów z dodatkowymi opcjami dla preprocesora
Załóżmy, że napisaliśmy program w C++ i zapisaliśmy go w pliku o nazwie
program.cpp.
Można podglądnąć jaki kod wygeneruje ostatecznie preprocesor, wydając
następujące polecenie:
Po takim wywołaniu kompilator wypisze na standardowe wyjście przetworzony
przez preprocesor języka C++ program prog.cpp i na tym zakończy
swoje działanie (nie wygeneruje kodu wynikowego).
Kompilując program można zdefiniować jakieś makro, które kompilator będzie
znał od początku. Należy wówczas posłużyć się wywołaniem z opcją
-D:
W przykładzie tym zdefiniowano nazwę NDEBUG, wykorzystywaną
w asercjach do generowania kodu testującego poprawność zadanych warunków
logicznych w programie; jeśli nazwa NDEBUG zostanie zdefiniowana,
to preprocesor nie wygeneruje żadnego kodu testującego warunki (wywołanie
makra assert(warunek) nie będzie generować żadnego istotnego kodu).
Opcji -D można także użyć do zdefiniowania makra z argumentami,
na przykład:
W kompilowanym programie będzie można posługiwać się wywołaniem makra
kwadrat(wyrażenie).
Jeśli potrzebujemy usunąć zdefiniowaną wcześniej makrodefinicję, to należy
się posłużyć parametrem -U, co ma zastosowanie przy kompilowaniu
programu składającedo się z kilku plików źródłowych: