język c++ ( programowanie ii ) rok akademicki...

130
Język C++ historia, współczesność, przyszłość Język C++ jest wieloparadygmatowym językiem programowania. Stworzony w latach osiemdziesiątych XX wieku przez Bjarne Stroustrupa C++98 ISO/IEC 14882:1998 C++03 ISO/IEC 14882:2003 C++11 ISO/IEC 14882:2011 C++14 ISO/IEC 14882:2014

Upload: vuthu

Post on 27-Feb-2019

215 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Język C++ historia, współczesność, przyszłość

Język C++ jest wieloparadygmatowym językiem programowania. Stworzony w latach osiemdziesiątych XX wieku przez Bjarne Stroustrupa

•C++98 ISO/IEC 14882:1998•C++03 ISO/IEC 14882:2003•C++11 ISO/IEC 14882:2011•C++14 ISO/IEC 14882:2014

Page 2: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

C++11/14 – dlaczego standard jest ważny?

Standard to brak zależności od• rodzaju kompilatora• systemu operacyjnego• CPUStandard odwołuje się / opisuje działanie abstrakcyjnej maszyny.Kompilator ma za zadanie zrealizować ten opis na konkretnym sprzęcie.

C++98/C++03 – abstrakcyjna maszyna była jednowątkowaC++11/C++14 – abstrakcyjna maszyna zaprojektowana jako wielowątkowa– model pamięci (organizacja pamięci i sposoby dostępu do pamięci)– na niskim poziomie gwarantowane operacje atomowe

w określonej kolejności

Page 3: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

C++ podstawowe cechy

• Główne cechy języka: • język kompilowalny, ogólnego przeznaczenia, określany

jako język „średniego poziomu” – dokument opisujący standard C++11 ma 1338 stron

• silna (statyczna) kontrola typów podczas kompilacji: pewna forma weryfikacji poprawności kodu, pozwalająca na wczesne wykrycie błędów lub niezamierzonego działania

• język swobodnego formatu, rozmieszczenie znaków na stronie nie ma znaczenia, ale każda instrukcja musi być zakończona średnikiem ;

• C++ nie wspiera własności specyficznych dla danej platformy lub niebędących własnościami ogólnego przeznaczenia

Page 4: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

C++ style programowania

• C++ nie narzuca żadnego stylu, daje programiście możliwość wyboru.

• programowanie proceduralne: organizowanie kodu w postaci procedur, wykonujących ściśle określone operacje, dane nie powiązane z procedurami, jako parametry wywołania procedur

• programowanie obiektowe: zbiór obiektów komunikujących się pomiędzy sobą w celu wykonywania zadań, obiekt to element łączący stan (dane) i zachowanie (metody)… programowanie funkcjami wirtualnymi

• programowanie uogólnione: kod programu bez wcześniejszej znajomości typów danych, szukanie i systematyka abstrakcyjnych reprezentacji efektywnych algorytmów, struktur danych i innych elementów programowych… programowanie szablonami

Page 5: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

C++ literatura (1) – kanon literatury

International Standard (można kupić – cena zaporowa)ISO/IEC 14882:2011(E)

C++11 Final Documentwww.open-std.org/jtc1/sc22/wg21/N3290 (2011-04-11)

Bjarne Stroustrup• Język C++• Programowanie. Teoria i praktyka

z wykorzystaniem C++ (Wyd. II popr.)

Page 6: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

C++ literatura (2) – „stare ale jare” (niestety, nie C++11)

Bruce EckelThinking in C++, vol. I i II (po angielsku – on-line)

Jerzy Grębosz• Symfonia C++ Standard (C++03)• Pasja C++ (niestety stare)

Page 7: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

C++ literatura (3)

Nicholas A. Solter, Scott J. KleperC++ Zaawansowane programowanie

Wydanie III po angielsku

Stephen PrataJęzyk C++. Szkoła programowania. Wydanie VI

Siddhartha RaoC++. Dla każdego. Wydanie VII

Page 8: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

C++ literatura (4)

D. Ryan StephensC++ Receptury(O’Reilly)

Anthony WilliamsJęzyk C++ i przetwarzanie współbieżne w akcji

David Vandevoorde, Nicolai M. JosuttisC++ szablony. Vademecum profesjonalisty

Aktualizacja w roku 2015

Nicolai M. JosuttisC++. Biblioteka standardowa. Podręcznik programisty

Wydanie II po angielsku

Page 9: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

C++ literatura (5)

Scott Meyers– „C++ 50 efektywnych sposobów na udoskonalenie

Twoich programów”– „Język C++ bardziej efektywny”– „STL w praktyce: 50 sposobów efektywnego wykorzystania”

Herb Sutter

– „Wyjątkowy język C++ 47 łamigłówek…”– „Wyjątkowy język C++ 40 nowych łamigłówek…” – „Niezwykły styl języka C++ 40 nowych łamigłówek…”– „Język C++ Standardy kodowania 101 zasad…”

(współautor: Andrei Alexandrescu)

KURSY DOSTĘPNE ON-LINEKarol „Xion” Kuczmarski – Kurs C++ (Megatutorial)Sektor van Skijlen – C++ bez cholesteroluPiotr Białas, Wojciech Palacz – Zaawansowane C++pl.wikibooks.org/wiki/C++ – niekompletny jeszcze…Frank B. Brokken – C++ Annotations Ver. 9.8.x

Page 10: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Twój edytor i kompilator

• Używanie gcc zamiast g++– GCC (GNU Compiler Collection) kompiluje różne języki (C, C++, Objective-C,

Objective-C++, Java, Fortran, Ada). gcc rozpoznaje kod źródłowy C++ po rozszerzeniach:

– gcc nie konsoliduje skompilowanego kodu z biblioteką standardową c++– jeśli użyjesz gcc to będziesz musiał podać ręcznie ścieżkę do plików

nagłówkowych oraz do biblioteki standardowej!

.C, .cc, .cpp, .CPP, .c++, .cp, .cxx

Nie utrudniajmy sobie życia i używajmy g++W przypadku Dev-C++ chodzi o zapisaniepliku źródłowego z rozszerzeniem .cpp

Page 11: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Kompilator i konsolidator: gcc.gnu.org (g++)

• Kompilator g++ – tłumaczy kod źródłowy na język assembler lub rozkazy komputera

• Konsolidator g++ (linker) – dopasowuje odwołania symboli do ich definicji

• Najnowsze wersje wspierają standard C++11 (wersja 4.9.1), a także C++14

• Program zarządzający bibliotekami ar, ranlib(archiver, librarian)– biblioteki statyczne .a (oraz pliki obiektowe .o) wymagane do

skonsolidowania pliku wykonywalnego podczas linkowania– biblioteki dynamiczne .so zawierają kod maszynowy ładowany

do pamięci po uruchomieniu wykorzystującego je programu, muszą więc być dostępne podczas uruchamiania programu

• Warto zapoznać się z narzędziem make

Page 12: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Kompilator – wsparcie nowego standardu

Kompilowanie kodu według nowego standarduWsparcie kompilatora dla standardu C++11 (C++14) wymaga dodatkowej opcji (flagi):

Przykładowo (linux):Program jest w katalogu /usr/binPliki nagłówkowe w katalogu /usr/include/c++/4.8Biblioteki w katalogu /usr/lib/gcc/i486-linux-gnu/4.8

Na pracowni komputerowej kompilator g++ 4.92 i nowszy jestdostępny tylko w nowych instalacjach (Dev-C++ 5.11)

g++ -std=c++11 …

g++ -std=c++14 …

Page 13: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Kompilowanie i linkowanie (konsolidacja)

Prosty program o nazwie myprog z pliku prog1.cc

Plik obiektowy (bez konsolidacji do programu)

Konsolidacja do programu wykonalnego

Uruchomienie programu (linux)

gdzie „ . ” (kropka) oznacza pełną nazwę ścieżki, chyba że ścieżka do katalogu z programem jest w zmiennej PATH

g++ -std=c++11 -o myprog prog1.cc // to samo: g++ -std=c++11 prog1.cc -o myprog

g++ -std=c++11 -c -o prog1.o prog1.cc

g++ -std=c++11 -o myprog prog1.o

./myprog

Page 14: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Kompilatory – kilka uwag

Można mieć zainstalowane kilka wersji g++ oraz biblioteki standardowej. Napisz: i postukaj „tab” (pokażą się wszystkie programy zaczynające się na g++)

Zwykle g++ to link symboliczny do jednej z wersji. Sprawdzenie wersji:

Inne kompilatory warte uwagi:

Kompilowanie plików nagłówkowych• niektóre kompilatory pozwalają na prekompilowanie plików nagłówkowych,

w dużych projektach znacznie może to przyspieszyć proces kompilacji• g++ kompilując plik .h tworzy plik z rozszerzeniem .h.gch• prekompilowany plik jeśli znaleziony, może być brany jako pierwszy przed plikiem .h• student robi to zwykle przez pomyłkę, niepotrzebnie umieszczając na liście plików źródłowych

do kompilowania również pliki .h (może to prowadzić do zaskakujących problemów w stylu „edytuję plik .h i nic się nie dzieje”)

g++ -v // lub: g++ --version

g++

clang ver. 3.7, Intel C++ ver. 15, Microsoft Visual Studio C++ 2015

Page 15: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Pierwszy program

Program wymaga napisania funkcji:

lub

W kodzie – tylko jedna funkcja main. Uwaga: dawniej (przed rokiem 1998) dopuszczano postać funkcji zwracającej void (tzn. „nic”), teraz musi zwracać int.

Paradoksalnie, jest to jedyna funkcja, w której (skoro „coś” zwraca) nie trzeba pisać instrukcji „return”. Można (ale nie trzeba) jawnie napisać:

int main() { }

int main() {return 0;

}

auto main() -> int { }

Page 16: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Pierwszy program: średnik

Uważaj na średnik – są miejsca, w których średnik jest konieczny, a są, w których jest zbędny lub nieprawidłowy.

Nie stawiaj średnika za nawiasem kończącym definicję funkcji – jest niepotrzebny!

Nie stawiaj średnika na końcu dyrektywy preprocesora – to jest błąd!

Średnik konieczny jest na końcu definicji klasy!

Przykład kompilującego siękodu, w którym przez pomyłkę mamy niezamierzone działanie…

#include ”mojplik.h” ;#define FLAGA ;

class Klasa { } ;

int fun3() {return 2;

} ;

for (int i=0; i<10; ++i);// tutaj instrukcja, którą może ktoś// zamierzał wykonać 10 razy…

Page 17: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

#include <iostream>using namespace std;

int main() {cout << "I am Jan B. " << "za zycia napisalem ponad " << 100<< " ksiazek!\n";cout << "A Ty ile napisales: ";int liczba;cin >> liczba;if (liczba < 100) cout << "\n…Tak malo!";return 0; // return EXIT_SUCCESS

}

Pierwszy program – który coś robi

#include <iostream.h> // NIE UŻYWAĆczasem implementowane tak:

#include <iostream> using namespace std;

w nowych kompilatorach ostrzeżenia, a nawet może się nie skompilować

Można też wybrać konkretneusing std::cout;using std::cin;Albo podczas wywołania pisaćstd::cout oraz std::cin itd.

Biblioteki z C:#include <cstdlib>#include <cstdio>#include <cassert>

Page 18: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Zajrzyjmy w głąb <iostream>

#include <ostream>#include <istream>

extern istream cin;extern ostream cout;extern ostream cerr;extern ostream clog;

Deklaracje obiektów odpowiadającychza pracę na strumieniu wejście / wyjście.Obiekty konstruowane przed main()

Hie

rarc

hia

klas

odpo

wie

dzia

lnyc

h za

pr

acę

na st

rum

ieni

ach

cin – obiekt odpowiedzialny za obsługę standardowego strumienia wejściowego (zwykle powiązanego z klawiaturą), wywołanie powoduje opróżnienie buforu coutcout – obiekt odpowiedzialny za strumień wyjściowy (zwykle powiązany z monitorem)cerr – obiekt standardowego strumienia komunikatów o błędach, powiązany przez system z monitorem, strumień niebuforowanyclog – obiekt wyprowadzany standardowo tak jak cerr, strumień buforowany

Page 19: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Operatory, manipulatory, znaki specjalne

operator<< oraz operator>> są to operatory przesunięcia bitowego, jednak dla obiektów strumienia są przeciążone i stają się „operatorami wejścia/wyjścia”

Co lepiej na końcu: std::endl czy \n ?MANIPULATORY ( tak naprawdę funkcje)endl – dodaje do buforu znak ’\n’ orazwykonuje flush – opróżnienie buforuends – wkłada znak kończący łańcuch znakowy, czyli symbol zerowy ’\0’ flush – opróżnia buforws – czyta i ignoruje białe znakiKod dla guru (przykład):

ostream& ostream::operator<<( ostream& (*op) (ostream&) ) {

return (*op) (*this); }std::ostream& std::endl (std::ostream& s) {

s.put('\n'); s.flush(); return s;

}

Można tak: std::cout << std::endl;lub tak: std::endl ( std::cout );

ZNAKI SPECJALNE (stałe znakowe)\n nowa linia\r powrót do początku linii\t pozioma tabulacja\a alarm dźwiękowy\0 symbol zerowy (koniec łańcucha)MNIEJ UŻYWANE\v pionowa tabulacja\b powrót o jedną pozycję\f nowa strona (drukarka)\? znak zapytaniaKONIECZNE W ŁAŃCUCHU ZNAKOWYM\\ lewy ukośnik\’ apostrof\” cudzysłów

Page 20: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Deklaracja – co to jest?

Deklaracja – to wprowadzenie w danej jednostce translacji (pliku) nazwy (lub nazw), albo redeklaracja nazw wprowadzonych poprzednimi deklaracjami.Deklaracje generalnie określają jak mają być rozumiane dane nazwy.Deklaracja może być też definicją, chyba że (i wtedy są to tylko deklaracje):• deklarujemy funkcję bez definiowania jej ciała

• deklaracja poprzedzona jest specyfikatorem extern, w znaczeniu obiektu zdefiniowanego w innym pliku

• deklaracja z użyciem extern jako sposób konsolidacji (linkowania) kodu

void fun( double d, short n, int );

gdy chcemy „zlinkować” z kodem z innego języka, musimy zadeklarować nazwy obiektów tam zdefiniowanych

extern ”C” int fun ( float );extern ”C” { /* tutaj lista deklaracj */ }

deklarujemy, że w innym pliku będzie zdefiniowana zmienna typu double o nazwie d. UWAGA: jeśli użyjemy specyfikatora extern oraz inicjalizujemy zmienną, np. extern double d = 3.14; to oznacza to już definicję a nie deklarację!

extern double d;

nie ma definicji (ciała) funkcji, czyli części ujętej w nawiasy { } to jest to tylko deklaracja

Page 21: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Deklaracje (2)

• deklarujemy statyczną składową w definicji klasy

• deklarujemy nazwę klasy (bez jej definiowania):• deklarujemy (silny) typ wyliczeniowy (C++11)

Deklaracjami nazywamy również:• deklarację z użyciem typedef

• deklarację użycia using lub dyrektywę using

class Foo;

zmienna statyczna w definicji klasy to dopiero jej deklaracja – jak się później dowiemy, taką zmienną definiuje się dopiero poza ciałem klasy

using std::cout;using namespace std;

class Foo {static int n;

};

„klasa wyliczeniowa” (albo „silny typ wyliczeniowy”) pozwala na uprzednią deklarację wraz ze specyfikacją typy danych wyliczeniowych (typ musi być całkowity)

enum class EColor;enum struct EShape : char;

deklaracja użycia czegośdyrektywa użycia którejś przestrzeni nazw

typedef int Calkowity, *PtrCalkowity;Calkowity n1; PtrCalkowity ptr1;

n1 jest typu int, zaś ptr1 jest typu „wskaźnik do int”

Page 22: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Definicje – reguła jednej definicji (One Definition Rule)

Jedna definicja – żadna jednostka translacji (plik) nie może zawierać więcej niż jednej definicji jakiejkolwiek zmiennej, funkcji, klasy, typu wyliczeniowego lub szablonu.

Definicja może się znajdować w programie, zewnętrznej bibliotece (standardowej, użytkownika).Definicja klasy konieczna jest w danym pliku, gdy typ klasy używany jest w sposób wymagający znajomości kompletnej definicji.

One ring to rule them all, one ring to find them,

One ring to bring them all and in the darkness bind them.

class Foo;struct Foo* ptr1;Foo *ptr2;

w tych przypadkach nie ma konieczności znajomości definicji klasy, wystarczy deklaracja jej nazwy

Czasami definicja może się „powtórzyć” w różnych plikach. Dotyczy to klasy, typu wyliczeniowego, funkcji inline (extern inline), szablonu klasy, statycznej zmiennej oraz metody składowej w szablonie klasy, niestatycznego szablonu funkcji, specjalizacji szablonu… (C++11 §3.2.5) – wszystko to pod pewnymi warunkami! (zasadniczo jest to powtórzenie tego samego kodu z ew. dopisanymi wartościami domyślnymi funkcji)

Page 23: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Organizacja kodu (header guard)

DEKLARACJE zmienny, funkcji nie-inline lub DEFINICJE funkcji inlineDEFINICJE klas, DEFINICJE szablonówplik nagłówkowy ( .h )Wielokrotne włączenie tego samegonagłówka (#include) – wielokrotna definicja – pogwałcenie reguły ODR – błąd!

Aby temu zapobiec, w plikach nagłówkowych zawsze korzystamyz dyrektyw preprocesora (blokada, tzw. header guard)

DEFINICJE zmiennych, funkcji, metod klasplik źródłowy ( .cc )

Cytat z „Megatutorial-u” Karola Kuczmarskiego(Państwa niewiele starszego kolegi…)

Dyrektywa #include jest głupia jak cały preprocesor.

Nie korzystamy z dyrektywy#pragma once• pierwotnie działała tylko w niektórych

kompilatorach, np. Visual C++• pragma nie jest polecana przez twórców gcc

jako dyrektywa z definicji „zależna od implementacji”, choć działa w g++ od ver. 3.4

#ifndef FIGURA_H#define FIGURA_H

// tutaj cała zawartość pliku

#endif // FIGURA_H

Page 24: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Pułapki myślenia o blokadach

header guard (czyli zestaw #ifndef #define … #endif) nie chroni przed problemem podczas konsolidacji plików, jeśli w pliku nagłówkowym, włączonym do tych różnych plików, zdefiniowaliśmy coś, co pogwałci ODR. Skompiluje się, ale linker zgłosi „multiple definition”header guard chroni jeden dany plik źródłowy przed wielokrotnym włączeniem (i kompilacją) tego samego pliku nagłówkowego, wielokrotne włączenie może nastąpić również nie wprost, przez inne włączane pliki

#ifndef H2_H#define H2_H#include ”h1.h”

// coś jeszcze#endif

#ifndef H1_H#define H1_H

void fun() { }#endif

#include ”h2.h” void fun2() { fun(); }

#include ”h1.h”#include ”h2.h”int main() {

fun();}

g++ main.cc test.cc –o prog/tmp/cccOPU18.o: In function `fun()':test.cc:(.text+0x0): multiple definition of `fun()'/tmp/ccGypJJH.o:main.cc:(.text+0x0): first defined herecollect2: ld returned 1 exit status

plik h2.h plik main.ccplik test.ccplik h1.h

Page 25: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Namespace – przestrzeń nazw

Namespace – „przestrzeń nazw” – obszar posiadający swoją nazwę lub bez nazwy, służący do deklaracji. Nazwy zdeklarowane wewnątrz namespace są „zamknięte” –odwołanie do nich możliwe jest poprzez nazwę przestrzeni nazw lub odpowiednią deklarację / dyrektywę użycia. Namespaces służą unikaniu kolizji nazewniczych.

Definicja namespace może być rozbita na wiele części i może się znajdować nawet w różnych plikach – zatem sami możemy nawet coś dodać do danej „przestrzeni nazw” – nawet tej zdefiniowanej w jakiejś zewnętrznej bibliotece.

inlineopcjonalnie namespace nazwaopcjonalnie { /* zawartość */ }

inline – nowość w C++11 – w celu wspierania różnych wersji danej biblioteki, czyli ewolucji kodu, ze wskazaniem na bieżącą (np. najnowszą) wersję

Cała biblioteka standardowa jest zamknięta w przestrzeni o nazwie stdKonieczna zatem jest dyrektywa użycia:

using namespace std;ale nigdy w pliku nagłówkowym! W plikach nagłówkowych raczej piszemy std::obiekt, ewentualnie stosujemy deklarację użycia, np. using std::cout

Page 26: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Namespace – reguły istnienia, tworzenia, użycia

Namespace – tylko w przestrzeni globalnejalbo (zagnieżdżone) wewnątrz innej przestrzeni

tym samym

using – deklaracja/dyrektywa użycia czegoś z przestrzeni nazw

void f();namespace A {

void g();}

namespace nie można zagnieździć (definiować) wewnątrz definicji funkcji (również main) ani nie można zdefiniować wewnątrz klasy

namespace X {using ::f; // globalne fusing A::g; // g z A

}void h() {

X::f(); // woła ::fX::g(); // woła A::g

}

namespace A {int i;

}namespace A1 {

using A::i;using A::i; // tu ok, można powtórzyć

}void f() {

using A::i;using A::i; // a tu błąd!

}

Page 27: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Namespace – użycie, zagnieżdżenia

Bezpośrednią nadrzędną przestrzenią nazw dla danej deklaracji jest ta przestrzeń, w której deklaracja po raz pierwszy się pojawia. Później definicja (danej deklaracji) może być w innym zakresie, ale z precyzyjną specyfikacją co do pierwotnego wystąpienia deklaracji.

namespace A {namespace B {

void f(); class C { void m(); };

}void B::f() {

extern void h(); // to jest deklaracja A::B::h}void B::C::m() { // definicja metody m()}

}Można dodawać kolejną zawartość przestrzeni nazw (nawet w kolejnych plikach) ale musi być to zrobione w tym samym zasięgu znaczeniowym.

namespace A {void f(int);

}using A::f; // f jest synonimem A::f;

// czyli A::f(int)namespace A {

void f(char);}void foo() {

f(’a’); // woła f(int)} // pomimo że f(char) istniejevoid bar() {

using A::f; // f jest synonimem A::f;// zarówno A::f(int) i A::f(char)

f(’a’); // woła f(char)}

Jeśli w dwóch różnych przestrzeniach te same nazwy – konflikt w momencie użycia

Page 28: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Typy danych oraz specyfikatory

Podstawowe typy wbudowane:

wchar_t – rozszerzony typ znakowy (wielkość zależna od implementacji)char16_t i char32_t – do reprezentacji znaków standardu UnicodeSpecyfikatory (rozszerzają lub zawężają, ze znakiem lub bez znaku)

• short int (inaczej: short), int, long int (inaczej: long), long long int(inaczej: long long) oficjalnie w C++11 ze wzg. na zgodność z C99

• float, double, long doubleTyp(dwa stany logiczne: true, false – to są stałe)

char, int, float, double

short – long, signed – unsigned

bool

• operatory: && || ! < > <= >= == !=• komendy sterujące: if, for, while, do, ? :• kompilator przekształca int w bool

true – odpowiednik wartości całkowitej 1 false - odpowiednik wartości całkowitej 0

nie nadawać stanu logicznego za pomocą operacji arytmetycznej (+ lub -)→ niejawna konwersja typów

Page 29: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

typedef, using

typedef – synonim typu istniejącego (nie żadna nowa definicja), najczęściej używany do uproszczenia zapisu (wiele razy w bibliotece standardowej) np.

using – może być użyte zamiennie jako typedef

typedef basic_fstream<char> fstream; // w nagłówku fstreamtypedef basic_string<char> string; // w nagłówku string

typedef std::vector<int>::iterator It;using It = std::vector<int>::iterator; // te dwie linie robią to samo

typedef const char* (*Fptr)( double );using Fptr = const char* (*) (double); // wskaźnik do funkcji,

też to samo co wyżej

Page 30: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Zasięg zmiennych, przesłanianie – przykład

int a = 1; // zmienna globalnanamespace mojeKlocki

{ int a = 7; int b = 8; }namespace { int c = 99;

// int a = 3; spowodowałoby kolizję ze zmienną globalną}

int main() {int a = 2;{

int a = 3, c = 100;for (int i=0; i<10; ++i); // nic nie robi, bo uwaga - gdzie kończy się instrukcjacout << "a lokalne = "<< a <<endl; // 3using namespace mojeKlocki;cout << "a lokalne = "<< a <<endl; // 3cout << "a z mojeKlocki = "<< mojeKlocki::a <<endl; // 7cout << "b z mojeKlocki = "<< b <<endl; // 8int b = 12;cout << "b lokalne = "<< b <<endl; // 12cout << "a nielokalne = "<< ::a <<endl; // 1cout << "c z nienazwanej przestrzeni " << ::c << endl; // 99, to też jest zmienna globalna

}cout << "a lokalne = "<< a <<endl; // 2

}

zakomentowanie globalnej zmiennej i próbaodwołania się do niej spowoduje błąd kompilacji

Page 31: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Rodzaje obiektów i ich cechy (static – global)

Obiekt globalny – istnieje przez cały czas wykonania programu– domyślnie łączony zewnętrznie– deklaracja extern – można użyć w innych plikach źródłowych– deklaracją static zasięg można ograniczyć do pliku

wystąpienia definicji (bez kolizji nazw)– lepszy sposób na „łączenie wewnętrzne” – użycie

nienazwanej przestrzeni nazw (namespace)– jeśli const, to zachowuje się jak static (chyba że extern const)– domyślnie inicjowany wartością zera

Statyczny obiekt lokalny – istnieje przez cały czas wykonania programu– deklaracja z modyfikatorem static– wartość takiego obiektu przetrwa między kolejnymi

wywołaniami funkcji– zasięg ograniczony jest do bieżącego kontekstu– w klasie – jeden egzemplarz dla wszystkich obiektów klasy– domyślnie inicjowany wartością zera

pam

ięć

stat

yczn

a

Page 32: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Obiekty globalne i statyczne (globalne) – przykłady

// w przestrzeni nazw lub przestrzeni globalnejint i; // domyślnie łączenie zewnętrzneconst int ci = 0; // domyślnie globalny const jest static (łączony wewnętrznie)extern const int eci; // jawna deklaracja łączenia zewnętrznegostatic int si; // jawnie static

// podobnie funkcje – uwaga – nie ma globalnych funkcji stałych (const)int foo(); // domyślnie łączenie zewnętrznestatic int bar(); // jawna deklaracja static

// nienazwana przestrzeń nazw jako polecany sposób na ograniczenie zakresu// widzialności nazw do danej jednostki translacjinamespace {

int i; // mimo łączenia zewnętrznego niedostępne // w innych jednostkach translacji

class niewidoczna_dla_innych { };}

Page 33: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Rodzaje obiektów i ich cechy (stack, heap)

Obiekt automatyczny – obiekt lokalny– przydział pamięci następuje automatycznie w chwili

wywołania funkcji– czas trwania obiektu kończy się wraz z zakończeniem bloku,

w którym został zaalokowany– zasięg ograniczony jest do bieżącego kontekstu– należy uważać na wskaźniki i referencje do obiektów

lokalnych– obiekt domyślnie nie jest inicjowany

Obiekt z czasem trwania określanym przez programistę– obiekt z pamięcią przydzielaną dynamicznie (operator new)– czas życia – do usunięcia operatorem delete– obiekt bez nazwy– identyfikowany pośrednio przez wskaźnik– zawieszony wskaźnik - wskazujący na nieobsługiwany obszar

pamięci (wskaźnik zwisający)– wyciek pamięci - obszar pamięci przydzielany dynamicznie na

który nie wskazuje żaden wskaźnik

stos

st

erta

Page 34: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Stałe (const) a preprocesor

• za pomocą preprocesora

od miejsca zdefiniowana do końca pliku

• modyfikator const

zasięg taki jak zasięg zmiennej, typ musi być określony, stała musi być zainicjalizowana

• stałej zdefiniowanej za pomocą preprocesora nie można śledzić – bo polega na zamianie jednego symbolu na np. podaną wartość, zdecydowanie definiujmy stałe jako zmienne danego typu

• preprocesor można czasem użyć jako sprytnej makrodefinicji, np. wypisywania kontrolnego zmiennych (za Bruce Eckelem):

wtedy gdzieś w kodzie: PRINT(”wartosc”, a );

#define PI 3.1415

const float pi = 3.1415;

#define PRINT (STR, VAR) cout << STR ” = ” << VAR << endl#define PR (x) cout << #x ” = ” << x << ”\n”

Page 35: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

auto – dedukcja typu (C++11)

auto – dawniej oznaczało tylko zmienną lokalną (automatyczną)• dedukcji typu w oparciu o typ inicjalizatora

lub typu zwracanego przez funkcję

• dedukcja odbywa się tak jak w szablonach, z wyjątkiem rozpoznawania listy { a, b, c }, którą auto widzi jako std::initializer_list<T> (gdzie T to typ a, b, c)

auto i = 7; // typ intauto x = wyrażenie // x będzie typu zwracanego przez wyrażenie

template<class T>int whatever(T t) {

T x; // równoważne do auto x poza szablonem};

Page 36: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

auto – zastosowania ( C++11 )

• przykłady

• działa również z operatorem new

• szczególnie wygodne do dedukcji typów iteratorów

• niestety, wewnątrz wyrażeń lambda auto nie działa

for( auto i = m.begin(); i != m.end(); ++i ) … // niech m jest typu map<int,string>const auto& y = m; // y jest typu const std::map<int, std::string>&

auto a = 7; // a jest typu intconst auto *ptr = &a, b = 5; // ptr typu const int*, b typu const intstatic auto d = 3.14; // d typu doubleauto x = { 1, 2, 3 }; // x typu std::initializer_list<int>

new auto(1); // alokowanym typem jest intauto z = new auto(’a’); // alokowanym typem jest char, z jest typu char*

Page 37: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

auto – zastosowania ( C++11 )

• zmienne zadeklarowane za pomocą auto są nadal wielkościami statycznymi, stąd niemożliwe jest:

• możliwe jest

• uwagaauto s = ”hello world”; // jest typu const char*auto& s = ”hello world”; // jest typu referencja do const char[12] czyli tablicy

void fun( auto arg ) { } // źle: autodedukcja typu argumentu niemożliwaclass Foo {

auto m = 1; // źle: autodedukcja typu zwykłej składowej klasy niemożliwa// bo np. auto m = f(); wprowadzałoby spory problem w szukaniu // właściwej interpretacji tego czym jest f()};auto tablica[5]; // źle: autodedukcja typu z którego zbudowana jest tablica

class Foo {static const auto n = 0; // static tak

};

Page 38: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

auto – nowe metody w kontenerach, nowa pętla for ( C++11 )

W kontekście auto przydatne są nowe metody kontenerów:• zwracają jawnie stałe iteratory: cbegin(), cend(), crbegin(), crend()

Nowa składnia dla pętli for (tzw. range-based loop)

Można przebiegać po tablicach, kontenerach oraz dowolnych typach wyposażonych w iteratory, zwracane przez begin() i end()

short tablica[5];for ( auto& t : tablica ) { t = -t; } std::unordered_multiset<std::shared_ptr< T >> obj;for ( const auto& r : obj ) cout << r; // wypisuje wskaźnik// pytanie: czemu powyższe przez referencję?

auto ci = m.cbegin(); // ci typu std::map<int, std::string>::const_iterator

vector<int> v { 1,2,3,4,5 };for ( int i : v ) cout << i << endl; // i bezpośrednio każdym elementem wektorafor ( auto i : v ) cout << i << endl; // to samo co powyżejfor ( int& i : v ) cout << ++i; // może być też referencją i zmieniać zawartość!for ( auto& i : v ) cout << ++i; // to samo co powyżejfor (const int i : v ) jakasMetoda( i ); // const/volatile też możliwe

w C++11 nie ma problemu zagnieżdżonychnawiasów szablonów, nie

trzeba rozdzielać spacją

Page 39: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

auto – referencje, modyfikatory ( C++11 )

Dla zmiennych nie zadeklarowanych wprost jako referencje, modyfikatory const/volatile na najwyższym poziomie są ignorowane:

Tablice i nazwy funkcji redukują się do wskaźników:

Jeżeli const/volatile nie na najwyższym poziomie, to zostają:

Za pomocą auto można deklarować więcej zmiennych w linii:auto zmienna = s, *ptr_zmienna = &s; // dedukcja typu inicjalizatora – ten sam typauto i = 3, d = 3.14; // błąd – rożne typy inicjalizatorów

const vector<int> w;auto v1 = w; // v1 typu vector<int>, const zignorowaneauto& v2 = w; // v2 typu const vector<int>& - ale jeśli przez referencję, to ok

double tablica[5];auto t1 = tablica; // t1 typu double* - to się nazywa ”array decay to pointer”auto& t2 = tablica; // t2 typu double(&)[5] – właściwy typ tylko jeśli przez referencję

auto i = 10; map<int, string> m;const auto *pi = &i; // pi jest typu const int*const auto& pm = m; // pm typu const map<int, string>&

Page 40: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Operatory

• zwracają wartości na podstawie argumentów (argumentu)• 18 poziomów ważności – nie uczyć się wszystkiego! raczej używać

nawiasów ( ) do czytelnego oddzielenia; niektóre zapamiętać• operatory =, ++, -- dodatkowo zmieniają wartość argumentu

(skutek uboczny, ang. side effect)• operator przypisania = kopiuje p-wartość do l-wartości• operatory matematyczne +, -, *, /, %

• można połączyć z operatorem przypisania +=, -=, *=, /=, %=• zatem np. b %= 4; równoważne jest b = b % 4;• operator % (modulo) tylko z liczbami typu całkowitego

• operatory relacji <, >, <=, >=, ==, != zwracają wartość logiczną• operatory logiczne && (iloczyn), || (suma)• operatory bitowe & (koniunkcja), | (alternatywa), ^ (różnica

symetryczna), ~ (bitowy operator negacji)

Page 41: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Operatory – ciąg dalszy

• operatory przesunięć <<, >>jeśli po lewej liczba ze znakiem, to przesunięcie >> nie musi być operacja logiczną• można łączyć z operatorem przypisania <<=, >>=• bity przesunięte poza granicę są tracone

• operatory jednoargumentowe ! (negacji logicznej), -, +• operatory adresu &, wyłuskania *, -> i rzutowania

• rzutowanie: float a = 3.14; int b = (int)a; albo int b = int(a);

• operatory alokacji i usuwania: new, delete• operator trójargumentowy ? :

co się stanie:

• operator , zwraca wartość ostatniego z wyrażeń• operator sizeof

int a = --b ? b : (b = -10); // jeśli b=1, to a=-10

Page 42: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Operatory – tabela ważności

Level Operator Description Grouping

1 :: scope Left-to-right

2

() [] . -> ++ --dynamic_cast static_cast reinterpret_cast const_cast typeid

postfix Left-to-right

3

++ -- ~ ! sizeof new delete unary (prefix)

Right-to-left* & indirection and reference (pointers)

+ - unary sign operator

4 (type) type casting Right-to-left

5 .* ->* pointer-to-member Left-to-right

6 * / % multiplicative Left-to-right

7 + - additive Left-to-right

8 << >> shift Left-to-right

9 < > <= >= relational Left-to-right

10 == != equality Left-to-right

11 & bitwise AND Left-to-right

12 ^ bitwise XOR Left-to-right

13 | bitwise OR Left-to-right

14 && logical AND Left-to-right

15 || logical OR Left-to-right

16 ?: conditional Right-to-left

17 = *= /= %= += -= >>= <<= &= ^= |= assignment Right-to-left

18 , comma Left-to-right

Page 43: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Operatory – rzutowanie

• static_cast (konwersje niejawne, zawężające, zmieniające typ – podczas kompilowania) int b = static_cast<int>(a);void *vp; int *num = static_cast<int*>(vp);

• const_cast (od typów z modyfikatowem const lub volatiledo takich samych typów bez modyfikatora lub w drugą stronę)

• reinterpret_cast (pełna odpowiedzialność użytkownika, bez kontroli)

• dynamic_cast (rzutowanie "w dół" od abstrakcyjnego typu ogólnego do typu pochodnego – zajdzie gdy operacja taka ma sens – podczas wykonywania programu)

Page 44: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Typy złożone w c++ (litania)

Poprzez złożone typy w języku c++ rozumie się:• tablice obiektów danego typu• funkcje, mające parametry danego typu, a zwracające void lub referencje

lub obiekty danego typu• wskaźniki do void lub obiektów, lub funkcji danego typu (włączając w to

statyczne składniki klasy)• referencje do obiektów lub funkcji (tzw. referencje lewej wartości i

referencje prawej wartości)• klasy, zawierające obiekty różnych typów oraz metody składowe, wraz z

odpowiednimi ograniczeniami dostępu• unie, które są rodzajem klasy, mogącej zawierać obiekt różnych typów, w

różnych chwilach czasu• typy wyliczeniowe, zawierające listę nazwanych stałych wartości• wskaźniki do niestatycznych składowych klasy

Page 45: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

enum – typ wyliczeniowy „konwencjonalny”

enum – autonomiczny typ wyliczeniowy

poważne mankamenty• możliwa niejawna konwersja z enum do int (może prowadzić

do błędów, jeśli ktoś takiej konwersji nie chce)

• „wyciekanie” identyfikatorów do zewnętrznego zakresu względem miejsca zdefiniowania typu wyliczeniowego (np. enum zdefiniowany w przestrzeni globalnej eksportuje nazwy wszędzie… kolizja nazw)

• nie można określić typu, na jakim zbudowane sa identyfikatory• niemożliwa jest uprzedzająca deklaracja typu wyliczeniowegonienazwany enum – ma sens właśnie przez to, że jego identyfikatory (z listy wyliczeniowej) są widziane na zewnątrz jako stałe (całkowite):

enum EPozycja {eAsystent, // 0eAdiunkt, // 1eProfesor // 2

};

definiowanie zmiennych podobnie jak dla typu wbudowanego:

EPozycja pracownik = eAsystent;

można też zadać wartośćenum EPozycja {

eAsystent = 5,eAdiunkt = eAsystent + 2,eProfesor

}; nie można robić inkrementacji: pracownik++;

int a = eAsystent; // ok, konwersja!pracownik = 3; // bez rzutowania to jest błąd

enum { jeden = 1, dwa = 2, cztery = 4 };

sizeof( EPozycja ) = ?… pewnie 4 ale… może być mniej

Page 46: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

enum – silny typ wyliczeniowy (C++11)

• nazwy z listy wyliczeniowej nie wyciekają na zewnątrz• nie następuje niejawna automatyczna konwersja na int

• można (opcjonalnie) zdefiniować typ (musi być całkowity), na którym zbudwany jest nowy enum (domyślnie – int) i dzięki temu kontrolować wielkość

• możliwa jest deklaracja wyprzedzająca

enum class nazwa { lista identyfikatorów };

enum Alert { green, yellow, election, red }; // standardowy, stary typ wyliczeniowyenum class Color { red, blue }; // nowy, silny, identyfikatory nieznane na zewnątrzenum struct TrafficLight { red, yellow, green }; // jak widać, nie koliduje z niczymAlert a = 7; // błąd: zwykły przypadek, nie ma konwersji z int na enumColor c = 7; // błąd: nie ma konwersji int->Colorint a2 = red; // ok: możliwa konwersja Alert::red->intint a3 = Alert::red; // błąd w C++98, ok w C++11int a4 = blue; // błąd: blue nieznane w tym zakresieint a5 = Color::blue; // błąd: brak konwersji Color->intColor a6 = Color::blue; // ok

enum class Color : char; // deklaracjavoid foo(Color* p); // teraz można już użyć

zamiast class może być struct

enum class Color : char { red, blue }; // sizeof( Color ) taki sam jak sizeof( char )

Page 47: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

std::array – tablica na miarę naszych czasów (C++11)

• łączy w sobie szybkość zwykłej C-tablicy z zaletami bycia kontenerem standardowym, czyli np. „wie jaki ma rozmiar”

• zawiera w sobie agregat; potrzebny nagłówek <array>• wielkość i przetrzymywany typ trzeba z góry określić

• można używać jak tablicę, albo odpytać daną pozycję metodą at(n), można zapytać o pierwszy – front() i ostatni – back() element

• metody empty() – true gdy pusta czyli… zrobiona tak: array<int, 0> a;• size() – rozmiar tablicy, max_size() – hipotetyczny maksymalny rozmiar• fill( const T& val ) – wypełnienie wszystkich elementów wartością val

array<int, 3> a = { 1, 3, 7 }; // znak = opcjonalny, ale…array<string, 2> b { { string("Windows"), "Linux" } }; // powyższe zagnieżdżenie to inicjalizacja wewnętrznego agregatu// ten zapis nie jest przejawem „uniwersalnej inicjalizacji” poprzez// initializer_list<T> ponieważ array nie ma napisanego konstruktora

Page 48: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Referencje – lewe ( T &, const T & )

Terminologia wprowadzająca

Referencja ( T & ) „zwykła” to jakby „przezwisko” na coś.„Przezwisko” nie może istnieć samo, bez powiązania z tym, co określa. Zatem referencja w momencie definicji musi być zainicjalizowana i nie może być przestawiona na coś innego.

Niestała referencja ( T & ) może wskazywać na l-wartość. Stała referencja ( const T & lub T const & ) może wskazywać na l-warość i p-wartość. W roli p-wartości może wystąpić obiekt, który nie musi być stały, jak i obiekt, którego nie wolno modyfikować (np. tymczasowy). Do tej pory nie można było rozróżnić, na co pokazuje stała referencja.

l-value (lewa-wartość, l-wartość) coś, co można zmodyfikować, np. poprzez przypisanie (stoi po lewej stronie = )r-value (prawa-wartość, p-wartość) coś, co stoi po prawej stronie operacji przypisania, często rozumiana jako niemodyfikowalne

Nie istnieją:• referencje do referencji• tablice referencji• wskaźniki do referencji

Page 49: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Referencje – zakazane cv, prawe ( T && ) (C++11)

Kwalifikatory cv dla referencji, są niedopuszczalne. Wprowadzone przez typedef, albo argument szablonu, są zignorowane.

Przykład

C++11 wprowadza referencję „p-wartości” ( && ), która ma służyć wskazywaniu na p-wartości, ale w rozumieniu takim, że można je modyfikować. Służyć to ma budowaniu semantyki (składni) „przenoszenia”. Pojawiają się dzięki temu „konstruktory przenoszące” (move constructors) i „przenoszące operatory przypisania” (moveassignment operator). Więcej o tym – w dalszej części wykładu.

pamiętajmy, że w c++ funkcjonuje pojęcie kwalifikatora cv, czyli const i/lub volatile, zatem to co piszemy o const, dotyczy też volatile

Nie istnieje:T & const

int a = 3;typedef int& RINT;const RINT aref = a;aref = 4; // teraz ma wartość 4

wbrew pozorom, aref jest referencją „l-wartości” do int, a nie do const intnapisanie const RINT tu oznacza nie const int&a próbę int& const – coś takiego jest ignorowane

albo innymi słowy: referencja musi być zadeklarowana z const, potem tego const nie można dołożyć na zasadzie zmiany typu deklarowanej referencji

Page 50: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Wskaźniki

Wskaźniki – zawierają adres i informację o typie (wyjątek: void*)T* – zwykły wskaźnik (do typu T)const T*, T const* – wskaźnik do stałego obiektu („gwarancja nietykalności”)

T* const – wskaźnik stały („gwarancja nieprzesuwalności”)

const T* const, T const* const – stały wskaźnik do stałego obiektuPonownie uwaga na typedef:

typedef int* pointer;typedef const pointer const_pointer;

const_pointer jest typu int* const,a nie typu const int*

const int ci = 10, *pc = &ci, *const cpc = pc, **ppc;int i, *p, *const cp = &i;

pc – wskaźnik na stały int, cpc – stały wskaźnik na stały int, ppc – wskaźnik do wskaźnika na stały int, p – wskaźnik na int, cp – stały wskaźnik na int

Page 51: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Wskaźniki – własności i arytmetyka

• wskaźnik jak tablica

można nimi operować jakby były tablicą, vInt[2] to samo co n[2]

• operacje ++ lub - -– są one inteligentne, tzn. na podstawie typu wskaźnika kompilator

wie o ile bajtów ma przeskoczyć• operacje + lub – ograniczone

– można dodawać lub odejmować liczby całkowite (operacja inteligentna tzn. z wykorzystaniem wiedzy na temat wskazywanego typu)

– nie można dodawać dwóch wskaźników– można odjąć dwa wskaźniki – wynikiem jest liczba elementów danego typu

znajdujących się pomiędzy nimi:

int *vInt = n; // wcześniej int n[10];vInt = &n[0]; // to samo

vInt – to adres początku tablicy (pierwszego jej elementu)vInt + 1 – to adres drugiego elementu tablicy*(vInt + 2) – to zawartość wskazywana pod adresem vInt + 2

* tu jakooperatorwyłuskaniazmiennejze wskaźnika

int tab[] = { 1, 2, 5, 7 }; int *p1 = tab; int *p2 = &tab[3];cout << p2 – p1 << endl; // 3

Page 52: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Wskaźniki – przykłady

• można dokonać zmian…

• nie wszystkie zmiany możliwe…nie można usunąć przydomka const z żadnego obiektu (można tylko rzutować)

double f1 = 0.;const double pi = 3.14;double *vZmienna = &f1;const double *vStala1 = &pi;const double *vStala2; // wskaźnik do stałego obiektu, jeszcze nie ustawionyvStala2 = vZmienna;*vZmienna = 25.;double * const vStalyZmienna = const_cast<double * const>( vStala1 );vZmienna = vStalyZmienna;

T & * - takie coś nie istnieje!

przydaje się jako argument funkcji,wtedy wskaźnik – argument, możnawewnątrz funkcji przestawić na inny adres

T * & - referencja do wskaźnika na typ T

Page 53: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Funkcje – argumenty, wartości zwracane

• funkcja to podprogram• funkcję identyfikuje jej nazwa, trzeba ją zadeklarować – wyjątek to funkcja main• definicja funkcji jest deklaracją, niemniej

starajmy się deklarować wszystkie funkcje• deklarację funkcji można zagnieździć w innej funkcji, ale definicji funkcji nie

można zagnieżdżać w innej funkcji (nawet w main)• funkcja może przyjmować dowolne parametry i zwracać dany typ lub nic nie

zwracać (wtedy piszemy void)

• nigdy nie zwracamy adresu (referencji) do obiektu lokalnego(czas jego życia się skończył…)

• main zwraca zawsze int – z przyczyn historycznych nie musimy wołać komendy return, kompilator nie napotkawszy jej wstawia na koniec bloku tej funkcji return 0;

void fun(); // nic nie zwraca, ale można wewnątrz funkcji napisać // pustą instrukcję wyjścia return;

int fun(string, int); // deklaracja nie wymaga podania nazw zmiennych, // ale dla czytelności kodu warto je pisać

auto fun( double ) -> double; // nowa notacja C++11 ( -> trailing return type )auto fun( char ); // możliwe w C++14 ale wtedy przed wywołaniem funkcja // musi być zdefiniowana, sama deklaracja nie wystarczy bo nieznany jest typ zwracany

Page 54: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Funkcje – sposoby przekazania parametrów

• sposoby przekazywania parametrów do funkcjivoid fun(float f); // przez wartość, do wnętrza funkcji tworzona jest kopia// obiektu f, więc oryginału nie można zmienić (uszkodzić)void fun(const float f); // to nie ma sensu, tworzona jest kopia// i nawet tej kopii nie da się zmienić, czytelniej więc byłoby // jako argument używać float f, a w pierwsze linii funkcji np.// const float& argf = f;void fun(float& f); // przez referencję (adres), można // modyfikować obiekt podawany jako parametrvoid fun(const float& f); // przez referencję do stałego obiektu,// optymalny sposób! – nie jest tworzona kopia, a argument jest// chroniony przed zmianąvoid fun(float&& f); // przez referencję do prawej wartości, większy sens// ma dla typów złożonych, które umożliwiają operacje przenoszeniavoid fun(const float&& f); // zwykle bez sensu, bo blokuje przenoszenievoid fun(float* f); // przez wskaźnik, można modyfikowaćvoid fun(const float* f); // wskaźnik do stałego obiektu, nie można modyfikować

Page 55: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Funkcje – wywołanie a parametry

• jaka jest różnica pomiędzy parametrem "przez referencję" i "przez wskaźnik"? Sposób wywołania funkcji:

• na temat dedukcji typu zwracanego przez funkcję:

auto f(); // zwracany typ nieznanyauto f() { return 5; } // zwracany typ intauto f(); // redeklaracja – okint f(); // błąd – traktowane jako deklaracja inne funkcjiauto f() { return f(); } // błąd, dopóki typ zwracany jest nieznany,

// nie można wołać rekurencyjnieauto suma(int i) {

if (i==1) return i; // zwracany typ teraz znanyelse return suma(i-1) + i; // można więc dalej wołać rekurencyjnie

}// taka funkcja może mieć wiele instrukcji return ale każda zwracająca taki sam typ

float mojaLiczba = 0.;fun(mojaLiczba); // przez referencję, tak samo jak przez wartośćfun(&mojaLiczba); // przez wskaźnik, trzeba podać adres obiektu za pomocą &

Page 56: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Funkcje – tablice argumentami, inline

• tablice jako argumenty funkcji nie są przekazywane przez wartość

• funkcje inline (krótkie, w celu szybkiego wywoływania)• treść rozwijana w miejscu ich wystąpienia, o ile nie jest zbyt skomplikowana• dla zwykłej funkcji: deklaracja (bez specyfikatora) w nagłówku

definicja w plku źródłowym poprzedzona specyfikatorem inline

• podobnie dla metody składowej (tylko definicja ze słowem inline)• wszystkie funkcje zdefiniowane wewnątrz klas są automatycznie inline• jeśli pobierany jest adres funkcji – nie następuje rozwinięcie

(w szczególności w procesie „debugowania” – krokowego śledzenia działania programu)

void func1(int a[], int rozmiar); // musimy podać rozmiarvoid func2(int *a, int rozmiar); // array-to-pointer decayvoid func3(int (&a) [10]); // tylko 10-elementowa tablicavoid func4(int macierz[][3], int rozmiar);

void fun();

inline void fun() { /* definicja */ }

Page 57: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Funkcje – wartości domyślne

argumenty domniemane (od prawej do lewej) tylko w deklaracji

• deklaracja argumentu domyślnego tylko raz(w danym zakresie ważności)• w deklaracji funkcji – deklaracje można powtarzać, ale

nie z powtórzonymi w nich wartościami domyślnymivoid fun(int a); // w deklaracjach można zmieniać

// nazwy zmiennych, tylko po co…void fun(int a = 5); // tak jest dobrze

• w definicji funkcji jeśli ta jest jednocześnie jej deklaracją• obiekty lokalne nie mogą być wartościami domyślnymi• w nowym (lokalnym) zakresie ważności możliwa jest deklaracja

z innymi wartościami domyślnymi – nie jest to dobra praktyka!

void fun(int a, void*, float = 3.14, char znak= '\0');

Page 58: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Funkcje – wartości domyślne, przykłady

void g(int = 0, ...); // ok, bo … (wielokropek) to nie argument, tylko ich listavoid f(int, int);void f(int, int = 7); // powtórzenie deklaracji z dodaną wartością domyślnąvoid h() {

f(3); // OK, woła f(3, 7)void f(int = 1, int); // błąd: niezależne od wartości domyślnych deklaracji

// z innego – zewnętrznego – zasięgu }void m() {

void f(int, int); // nie ma wartości domyślnychf(4); // błąd: niepoprawna liczba argumentówvoid f(int, int = 5); // OKf(4); // OK, woła f(4, 5);void f(int, int = 5); // błąd: nie można redeklarować, nawet

// z taką samą wartością domyślną}void n() {

f(6); // OK, woła f(6, 7)}

Page 59: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Funkcje – dowolna liczba argumentów

int suma ( int liczba, … ) {va_list ap; // utworzenie zmiennej typu va_list (variable argument list)va_start( ap, liczba ); // ustawienie ap na pierwszy, jawnie podany, argumentint sum = 0;for (int i = 0; i < liczba; ++i ) {

sum += va_arg( ap, int ); // odczyt kolejnej zmiennej, sami określamy jej typ!}va_end( ap ); // porządkowanie stosu, ustawienie ap na 0return sum;

}int main() {

cout << sum(3, 1, 1, 1, 1, 1) << endl; // OK, możemy mniej liczyć, 3cout << sum(8, 1, 1, 1, 1, 1, 1) << endl; // śmieci, wyszliśmy poza listę

}

… - wielokropek umożliwia napisanie funkcji przyjmującej dowolną liczbę argumentów• Przynajmniej jeden (pierwszy) argument takiej funkcji musi być podany jawnie.• Obsługa (odczyt) takich argumentów za pomocą makr, pochodzących z języka C.• Konieczne włączenie nagłówka <cstdarg> ( lub stdarg.h )

Wady: argumenty poza kontrolą typów. Popularne przykłady z biblioteki: printf, sprintf

Page 60: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Funkcje – argumenty funkcji main

int main(int argc, char* argv[]) { // …to samo:

int main(int argc, char** argv) { // …

• argc – liczba argumentówpierwszym zawsze jest ścieżka i nazwa programuargv[0] – zapisana w pierwszej pozycji tej tablicy

• kolejne argumenty można konwertowaćpo włączeniu nagłówka #include <cstdlib>za pomocą funkcji: atoi(), atol(), atof()

• możemy wykorzystać obiekt klasy istringstream– klasa ta dziedziczy po klasie istream, ta zaś dziedziczy po klasie ios, zaś ta

po klasie ios_base– oznacza to, że obiekt ten "ma w sobie" wszystkie funkcje zdefiniowane

w powyższych klasach– ponadto ma zdefiniowaną własną funkcję:

void str(const string& tekst) const;string str() const;

Page 61: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Pomiędzy innymi typami a „łańcuchem znakowym”

#include <string>// konwertuje zmienną typu int na łańcuch znakowy std::stringstd::string to_string( int value );// taki sam, gdy działało sprintf o odpowiednio dużym buforzestd::sprintf(buf, "%d", value); // podobnie pozostałe:std::string to_string( long value );std::string to_string( long long value );std::string to_string( unsigned value );std::string to_string( unsigned long value );std::string to_string( unsigned long long value );std::string to_string( float value );std::string to_string( double value );std::string to_string( long double value );

Warto wiedzieć, że sytuacja, gdy „skazani byliśmy” na printf (sprintf) nie ma już miejsca!W nagłówku <string> dostępna jest seria przeciążonych funkcji to_string, działającychkomfortowo i bezpiecznie z punktu widzenia kontroli typów.Nie musimy się też martwić o wielkość wypełnianego buforu!

Page 62: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Pomiędzy „łańcuchem znakowym” a innymi typami

#include <string>// konwertuje łańcuch znakowy std::string na typ całkowityInt stoi( const std::string& str, size_t *pos = 0, int base = 10 );long stol( const std::string& str, size_t *pos = 0, int base = 10 );long long stoll( const std::string& str, size_t *pos = 0, int base = 10 );unsigned long stoul( const std::string& str, size_t *pos = 0, int base = 10 );unsigned long long stoull( const std::string& str, size_t *pos = 0, int base = 10 );

// konwertuje łańcuch znakowy std::string na typ zmiennoprzecinkowyfloat stof( const std::string& str, size_t *pos = 0 );double stod( const std::string& str, size_t *pos = 0 );long double stold( const std::string& str, size_t *pos = 0 );

Podobnie w drugą stronę, jeśli mamy łańcuchy znakowe (np. parametry programu), możemyteraz skorzystać z następujących funkcji konwersji. Działają one następująco: opuszczają białe znaki, czytają cyfry (tak wiele ile jest poprawne dla ustawionej bazy base, resztę ignorują), jeśli podstawi się jako drugi parametr niezerowy wskaźnik, to wpisane w niego zostaje adres pierwszego nieskonwertowanego znaku oraz jego indeks.

Page 63: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Klasa std::string

Utworzenie obiektu typu std::string odbywa się podobnie jak dowolnej zmiennejtypu wbudowanego. Jednak w tym przypadku można też stworzyć obiektzainicjalizowany danymi – obiekt budowany jest przez specjalną metodę składową,konstruktor. Konstruktorów może być dowolnie wiele, muszą różnić sięargumentami.

#include <iostream>#include <string>

using namespace std;

auto main() -> int {string s1; // pusty string

}

Zbadajmy jaki jest rozmiar i bufor obiektu s1:

for (auto i(0); i<1025; ++i) {s1 += ”a”;cout << s1.size() << ” – ”

<< s1.capacity() << endl;}

Dodatkowo co będzie gdy:s1.clear();s1.empty(); // zwraca true lub falses1.shrink_to_fit();s1.reserve(57); // jakie capacity() ?

Page 64: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Tworzymy kolejne obiekty std::string

Oto kilka sposobów na utworzenie / przypisanie obiektu typu std::string

Działania na stringach bez problemu:

const char *t = ”tekst do inicjalizacji”;s1 = t;string s2( s1); // obiekt „na wzór” istniejącego wcześniejstring s3( t, 8 ); // pierwsze 8 znakówstring s4( s2, 6, 8 ); // od 6-tego do 6+8 -mego, czyli…string s5( 100, ’*’ ); // chcę mieć sto gwiazdekstring s6 = ”konstrukcja”;string s7 = { ”uniwersalna inicjalizacja” }; // = opcjonalnie

s1 = s1 + ” drugi ” + s2;s1 += s6;

Page 65: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Rozmiary, usuwanie…

Maksymalny rozmiar i pewna stała:

Sprawdźcie jaka jest wartość tej stałej:

Wielkie usuwanie (erase – metoda składowa):

Specjalne funkcje adresowe (zwracające tzw. iteratory czyli obiekty „udające”wskaźniki – przechowalniki adresu i wiedzy o typie):

max_size() // zwykła metoda składowastring().max_size(); // string „w locie”

erase( nr_od, nr_ile ); // zwraca „referencję do”erase( adres_od, adres_do ); // zwraca „adres” nast. znaku

std::string::npos

begin(); // adres początku „zerowej pozycji”end(); // adres za ostatnim elementem, „za-ostatni”

Page 66: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Usuwanie…

Przykład, dodatkowo z algorytmem find:#include <iostream>#include <algorithm>#include <string>using namespace std;int main () {

std::string s = "To jest dobry przyklad";std::cout << s << '\n';

s.erase(0, 3); // usuń "To "std::cout << s << '\n';

s.erase(std::find(s.begin(), s.end(), ' ')); // usuń pierwszą spację ' 'std::cout << s << '\n';

s.erase(s.find(' ')); // Znajdź kolejną i usuń wszystko od niej do końcastd::cout << s << '\n';

}

Page 67: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Małe ćwiczenie

Narysujmy za pomocą „erase” taką sekwencję…******************************************************************I tak dalej…

#include <iostream>#include <string>using namespace std;

int main () {string str (20, ’*’);while ( ! str.empty() ) {

cout << str << endl;str.erase(str.end()-1);

}}

Page 68: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Wczytywanie z pliku

Utwórzmy obiekt do obsługi strumienia plikowego i wczytajmy… a potem wypiszmy!#include <fstream>

string s10;string str;cout << "Wprowadz tekst: ";cin >> str; cout << "Wczytano to: " << str << endl;getline (cin, str, '@'); // koniec = znaczek @cout << "Wczytano tamto: " << str << endl;

ifstream plik("tekst.txt"); // np. wziąć z: pl.lipsum.comwhile ( ! plik.eof() ) {

getline (plik, str);s10 += str; // czego tu brakuje? Znak końca linii… + ’\n’

}// wypiszcie na ekran… cout << s10;

Bufor cin nadal trzyma starą zawartość, tu poczytajcie jak to wyczyścićhttp://cpp0x.pl/kursy/Kurs-C++/Poziom-1/Obsluga-strumienia-wejsciowego/12

Page 69: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Przebiegamy po stringu…

String to forma kontenera sekwencyjnego… jakby tablicy znaków…

ITERATOR – inteligentny „pośrednik” pomiędzy kontenerami (zasobnikami),„wskaźnik” z adresem do operacji na konkretnych typach, strumieniach…

ITERATOR STRUMIENIA

copy (s1.begin(), s1.end(), ostream_iterator<char>(cout,"\n"));// używamy algorytmu copy (ten z nagłówka <algorithm>)// tworzymy w locie iterator strumienia wyjściowego, ostream_iterator// konieczny nagłówek #include <iterator>

s1 = "wlazl kotek na plotek i mruga";for ( auto c : s1 ) cout << c << " "; // range-based loopfor ( auto& c : s1 ) c = ( c==’w’ ) ? ’W’ : c; // zamieniamy na wielkie W, co z nawiasami?

for ( int i=0; i < s1.length(); ++i ) cout << s1[i] << " ";

string::iterator it; // na razie pusty auto it = s1.begin();it = s1.begin(); // początek … end() koniecwhile ( it != s1.end() ) { cout << *it << endl; ++it; }

Page 70: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Typy abstrakcyjne – klasa i obiekt

• Z myślenia w kategoriach "jak to zrobić" przechodzimy do myślenia bezpośredniego nad zagadnieniem, czyli "co zrobić"

• Odwrócona kolejność tworzenia: opis danych, przepływ danych, algorytmy

• Najważniejsze są dane, na których operujemy

• klasa– matryca, "plan" według którego powstaje obiekt (opisana zawartość,

a także sposób utworzenia – konkretyzacji)– nowy typ danych zawiera w sobie składniki danych innego typu oraz funkcje

(metody) – enkapsulacja (kapsułkowanie)• obiekt

– obiekt to egzemplarz klasy– samodzielna, ograniczona jednostka posiadająca zespół cech i zachowań– każdy obiekt ma własną kopię atrybutów (wyjątek: dane statyczne),

metody (ich implementacja) są wspólne– obiekty współpracują ze sobą, działanie jest "na rzecz" jakiegoś obiektu

Page 71: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Kiedy klasa jest dobra?

• klasa – reprezentuje wspólne właściwości grupy obiektów– czy istnieje potrzeba tworzenia więcej niż jednego

egzemplarza klasy? (są specjalne wyjątki – singleton)– jeśli nie ma różnić pomiędzy egzemplarzami klasy:

prawdopodobnie taka klasa powinna być wartością– nie jest tylko pojemnikiem na dane, które mogą być

modyfikowane przez funkcje– udostępnia uproszczony obraz złożonego bytu, określa

dopuszczalne do wykonania czynności

• co nie jest (dobrą) klasą– zgrupowanie kilku funkcji– kontener na dane (typu struktura w C) tylko

z funkcjami typu set i get)

Page 72: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Cele klasy

• cel klasy

– powinien być dobrze zdefiniowany, a klasa łatwa do zrozumienia i prosta w użyciu

– nie należy dodawać do klasy metod zupełnie z nią nie związanych, tylko po to aby zaspokoić oczekiwania grupy klientów

– jeśli klient po zetknięciu z klasą nie jest pewien do czego ona służy, projekt może być słaby i niepoprawny

– wielkość klasy: jeśli liczba metod przekracza 15-25, to warto się zastanowić czy nie należałoby z jednej "wielkiej" klasy zrobić kilka mniejszych, czytelniejszych

Czy potrafisz określić cel klasy w jednym zdaniu?

Page 73: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Obiekt – własności

• obiekt – powołuje klasę do życia– stan obiektu jest sumą wszystkich statycznych i dynamicznych

wartości jego właściwości, właściwość jest niepowtarzalną cechą obiektu

– stan obiektu określają typy proste lub złożone– to, jak obiekt reaguje na nasze polecenia i co robi z innymi obiektami,

zależy od jego stanu– stan obiektu kontrolują metody, zwykle metody wywoływane są

przez klienta (wyjątek to metody np. do obsługi błędów, przerwań)• zachowanie obiektu

– sposób, w jaki obiekt działa i reaguje na komunikaty– komunikat może zmienić stan obiektu, może też spowodować

wysłanie komunikatów do innych obiektów– metody stałe: takie, które (gwarantują, że) nie zmieniają stanu

obiektu– wszystko co nie powinno być dostępne dla normalnego klienta,

powinno być ukrywane

Page 74: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Model obiektowy

• model obiektowy– w uproszczeniu: można myśleć o klasach jak o rzeczownikach,

a o ich metodach jak o czasownikach– kluczowe elementy modelu obiektowego

• abstrakcja danych• hermentyzacja• hierarchia

abstrakcja danychwynik definiowania klas, koncentrujemy się na zewnętrznym wyglądzie obiektu i oddzielamy ważne zachowania od wewnętrznych szczegółów implementacji

hermetyzacja (ukrywanie danych)wynik ukrywania wewnętrznych szczegółów implementacji, istotna w momencie rozpoczęcia implementacji

hierarchiasposób tworzenia wzajemnych relacji pomiędzy abstrakcjami danych

Page 75: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Typy hierarchii

"jest-czymś", realizowane poprzez dziedziczenie, umoż-liwia stosowanie relacji ogólne-specyficzne

"ma-coś", budowanie z elementów składowych, wprowadza stosunek część-całość

RACHUNEK BANKOWY

ROR LOKATA

jest:

SAMOCHÓD ma:

silnik siedzenie

koło kierownica

Page 76: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Zalety modelu obiektowego

• zachęca do tworzenia systemów, które mogą podlegać zmianom, systemy są elastyczne i stabilne

• myślenie w kategoriach (klas i) obiektów jest naturalne dla człowieka

• oddzielenie klienta i programisty (hermetyzacja danych)

• wielokrotne wykorzystanie prostych klas, unikanie replikacji kodu

• rozszerzalność projektów (np. poprzez dziedziczenie), czyli zachęta do ponownego wykorzystywania istniejącego oprogramowania

Page 77: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Interfejs i implementacja

• interfejs to punkt widzenia użytkownika na to, jak obiekt wygląda i co można z nim zrobić

• klient używa klasy bez wgłębiania się w jej wewnętrzne działanie, dobrze zaprojektowany interfejs spełnia wymagania użytkownika

• specyfikacja interfejsu – w plikach nagłówkowych• implementacja określa w jaki sposób coś jest

wykonywane, model obiektowy pozwala na ochronę implementacji (przed klientem)

• model obiektowy pozwala na zmienianie implementacji podczas gdy interfejs pozostaje niezmieniony

Page 78: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Klasa

KLASApodstawowa jednostka

abstrakcji danych w języku C++

• posiada trzy regiony dostępu: prywatny, chroniony i publiczny

• zawiera sygnatury – metod niestatycznych i statycznych – deklaracje danych składowych zwykłych i statycznych

• może zawierać deklarację (definicję) innej klasy – zagnieżdżonej

Nazwy deklarowane w klasie = zakres ważności to obszar całej klasy. Domyślna etykieta dostępu (odwrotnie niż w strukturze) private

Page 79: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Dostęp do składników klasy

class MojaKlasa {

public:

int nr_pokoju;std::string etykieta;

int getNr();string getName();

};

dane składowe powinny być zdecydowanie w części prywatnej!

Dostęp do składników klasy:

MojaKlasa mojObiekt;MojaKlasa *mojWskaznik = &mojObiekt;MojaKlasa &mojaReferencja = mojObiekt;

mojObiekt.nr_pokoju;mojWskaznik->etykieta;mojaReferencja.getName();

Skąd zwykła (niestatyczna) metoda wie, na jakim komplecie danych (na jakim obiekcie) pracuje?

Otrzymuje niejawnie specjalny wskaźnik: this

zawiera adres konkretnego obiektu danego typu

Page 80: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

this is it (kilka słów o „tym” wskaźniku)

(stały) wskaźnik this – niejawnie zdefiniowana składowakażdej (niestatycznej) metody klasy, zawiera adres obiektu

this przekazywany jest jako parametr (niejawny) niestatycznym metodom klasy, aby znały adres obiektu, na którego zmiennych działają

typ wskaźnika this zależy od atrybutów metody (const, volatile), jeśli metoda jest const (volatile), to podobnie wskaźnik this (wtedy jest stałym wskaźnikiem do stałego obiektu)

void Prostokat::ustawParam(double x, double y) {this->bokX = x; // można jawnie zapisać, ale nie trzebathis->bokY = y;

}

Page 81: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

przypadki użycia wskaźnika this

• jawne użycie this – w przypadku kopiowania obiektu, sprawdzenie żeby obiekt się nie chciał sam na siebie skopiować (jak zobaczymy później: standardowe w operatorze przypisania =)

• nie wolno używać this do usuwania obiektu (np. delete this), za wyjątkiem sytuacji specjalnych – obiekt umieszczony jest w pamięci dynamicznej za pomocą operatora new „z umieszczeniem”, wtedy „ręcznie” sterujemy kreacją i destrukcją obiektu

void Prostokat::kopiuj(const Prostokat& figura) {if (this != &figura) { // tu sprawdzamy czy nie to samo

bokX = figura.bokX; bokY = figura.bokY;

} }

Page 82: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Klasa – prawa dostępu

public: protected: private:

public• dostęp bez

ograniczeń (z wnętrza i poza zakresem klasy)

• tutaj jest interfejs• składniki to funkcje

protected• tak jak private,

plus dostęp dla klas pochodnych(dziedziczenie) private

• dostęp tylko z wnętrza klasy (z zewnątrz dla klas lub fukcji - przyjaciół)

• tutaj szczegóły implementacji

w dowolnej kolejności

etykiety mogą się powtarzać

domyślny

Page 83: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Klasa – konstruktor

class Trivia {int i; float f;

public:Trivia(int n=0);Trivia(int k, float d);~Trivia();

};

konstruktor ( c-tor )• funkcja wywołana podczas tworzenia obiektu,

po przydzieleniu (lub wskazaniu miejsca w) pamięci• nazwa taka sama jak nazwa klasy• niczego nie zwraca (ale nie piszemy void)• może występować w wielu odmianach, z różną liczbą

argumentów (przeciążone wersje)• „domyślny” – taki, który można wywołać bez podania

parametrów (czyli bezparametryczny lub z wartością/warościami domyślną/domyślnymi argumentów

Czym się różni:Trivia::Trivia(int n) { i=n; f = 0; } // tu jest przypisanie

od:Trivia::Trivia(int n) : i(n), f(0) { } // tu jest inicjalizacja

Czy można pomieszać kolejność:Trivia::Trivia(int n, float d) : f(d), i(n) { /* … */ }

„Można”, ale to wcale nie zmienia kolejności tworzenia obiektów (najpierw i, potem f), a kompilator ostrzeże o odwrotnej (niż zapisana w kodzie) inicjalizacji!

lista inicjatorów konstruktora, „miejsce”, gdzie powstają i są inicjalizowane obiekty otwarcie { oznacza skonstruowanie obiektu

Page 84: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Klasa – destruktor

class Trivia { // to co poprzednio~Trivia();

};

destruktor ( d-tor )• funkcja wywoływana podczas usuwania obiektu• nazwa taka jak nazwa klasy poprzedzona znaczkiem ~• jest tylko jeden destruktor, niczego nie zwraca• destruktor nie może mieć żadnych parametrów• destruktor powinien „posprzątać” wszelkie dynamicznie

zaalokowane wewnątrz klasy zasoby• operator delete najpierw woła destruktor (potem zwalnia

pamięć)• zgłoszenie wyjątku gwarantuje posprzątanie obiektów na

stosie (wywołanie ich destruktorów)• wyskok za pomocą instrukcji goto też wywołuje destruktor

Trivia::~Trivia() { cout << "Good bye" << endl; }

Page 85: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Konstruktor kopiujący T::T (const T&)

• służy do skonstruowana obiektu, który jest kopią innego, już istniejącego obiektu tej klasy (inicjalizator kopiujący)Foo::Foo( Foo& );

– może posiadać również argumenty domyślneFoo::Foo(Foo&, float = 3.14);

– może być w postaci Foo::Foo( const Foo& );Foo::Foo( volatile Foo& );Foo::Foo( const volatile Foo& );

• jeśli go nie ma, kompilator sam go utworzy, na zasadzie tworzenia wiernej kopii (bit po bicie)

Page 86: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Konstruktor kopiujący T::T (const T&)

• generowany konstruktor kopiujący bezpieczny (const) chyba że któryś składnik klasy ma swój konstruktor kopiujący bez przydomka const

• jeśli klasa zawiera obiekty abstrakcyjne, to do kopiowania wołane są ich konstruktory kopiujące

• kiedy pracuje copy constructor:– wywołanie jawne (inicjalizacja przez przypisanie)

– przekazanie jako argument funkcji przez wartość– zwrócenie wartości funkcji (obiekt tymczasowy

inicjalizowany konstruktorem kopiującym – zależy od optymalizacji kompilatora)

Foo nowy = stary; // stary też klasy FooFoo nowy = Foo(stary);// ale nie: nowy = stary; tu pracuje operator =

Page 87: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Konstruktor kopiujący – kiedy konieczny?

class A {// klasa bez konstruktora kopiującegoint numer;char* nazwa;

};// gdzieś w programie:// konstruktor tworzy dynamiczną tablicę, // do której kopiuje słowo "Trzy"A a1(3, "Trzy"); A a2 = a1; // a2 to wierna kopia a1a2.setNumber(4);a2.setName("Cztery");cout << "a1 nazwa: " << a1.getName(); // "Cztery" !

• Prawdziwa tragedia w chwili likwidowania obiektów, destruktory dwa razy spróbują usuwać tablicę pod tym samym adresem

• Analogiczny problem mamy gdy stosujemy operator przypisania =• Zwykle w klasie, w której występują wskaźniki, konieczne jest napisanie

konstruktora kopiującego

A::A(const A& src) {numer = src.numer;nazwa = new char[src.strlen()+1];strcpy(nazwa, src.nazwa);

}

Page 88: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

#ifndef TSTRING_H#define TSTRING_H#include <cstring>// w pliku nagłówkowym NIE// otwieramy przestrzeni std

class TString {public:// interfejs

private:// implementacja// składowe klasy

protected:// póki nie będziemy dziedziczyć, // to pole nas nie interesuje

}; // pamiętaj o średniku#endif

Zbudujemy klasę

Definicję klasy zapiszmy w pliku tstring.h Zapiszmy też prosty plik main.cc

class TString {private:

char* ptr; std::size_t size;

};

pola dostępu do klasy

z zewnątrz

size_t jest nazwą (typedef) na bezznakowytyp całkowity wystarczająco pojemny aby opisać wielkość dowolnego obiektu[ m.in. zwracany przez sizeof ]

#include ”tstring.h”#include <iostream>using namespace std;int main () {

TString s1;}

Page 89: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

class TString {public:TString( const char* s = nullptr );

};

Zdefiniujmy konstruktor

Zdeklarujmy konstruktor (c-tor) : Metody definiujemy w tstring.cc

if (s > 0) {size = strlen(s);ptr = new char[ size + 1 ];strcpy( ptr, s );

}#ifdef DEBUG

cout << "TString c-tor " << size << " - " << ( ptr ? ptr : "pusty" ) << endl;#endif}

#include ”tstring.h”#include <iostream>

using namespace std;

TString::TString( const char* s ) : ptr(nullptr), size(0) {

Możemy teraz dopisać w main kolejny obiekt, np.TString s2("inicjalizacja slowem");

Kompilujemy dodatkowo dodając w liniiopcję –D definiowananazwaczyli –D DEBUG (może być bez spacji), przykładowo:g++4.8 –std=c++11 –DDEBUG

main.cc tstring.cc –o prog

Page 90: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

class TString {public:TString( const char* s = nullptr );~TString();

};

Zdefiniujmy destruktor

Zdeklarujmy destruktor (d-tor):

TString::~TString() {

#ifdef DEBUGcout << "TString d-tor " << size << " - " << ( ptr ? ptr : "pusty" ) << endl;

#endif

delete [] ptr;}

Śledzenie pokrokowe programu (debuger) gdbKod trzeba skompilować z flagą –g (oraz nie używać flag optymalizujących takich jak –O –O2 itd.)http://www.yolinux.com/TUTORIALS/GDB-Commands.html

Definicję destruktora, jak i wszystkich kolejnych metod składowych klasy, dopisujemy jako ciąg dalszy (czyli poniżej definicji konstruktora) w pliku tstring.cc

w pliku tstring.cc jako dalsza część

Page 91: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

class TString {public:

TString( const char* s = 0 );TString( const TString& s );

~TString();};

Zdefiniujmy konstruktor kopiujący

Zdeklarujmy konstruktor kopiujący (cc-tor): Możemy dopisać w main.cc

if (size > 0) {ptr = new char[ size + 1 ];strcpy( ptr, s.ptr );

}

#ifdef DEBUGcout << "TString cc-tor " << size << " - " << ( ptr ? ptr : "pusty" ) << endl;

#endif}

Operacja podobna do tej z konstruktora.

// poniżej to nie jest przypisanieTString s3 = s2; // albo tak:TString s3 ( s2 ); // albo tak:TString s3 { s2 };

TString::TString( const TString& s ) : ptr(nullptr), size( s.size ) {

w pliku tstring.cc jako dalsza część

Page 92: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

class TString { public:TString& operator=

( const TString& s );};

Zdefiniujmy operator przypisania kopiujący

Zdeklarujmy operator= kopiujący: Możemy dopisać w main.cc

if ( this != &s ) { // if ( *this != s ) {delete [] ptr; ptr = nullptr; size = s.size;if ( size > 0 ) {

ptr = new char[ size + 1 ];strcpy( ptr, s.ptr );

}}

#ifdef DEBUGcout << "TString copy operator= " << size << " - " << ( ptr ? ptr : "pusty" ) << endl;

#endifreturn *this; // nie zapomnij zwrócić obiektu!}

this – specjalny wskaźnik, który otrzymuje każda niestatyczna składowa klasy, a w którym zapisany jest adres bieżącego obiektu, na którego argumentach działać ma metoda

// poniżej jest przypisanie, bo obiekt// po lewej już istniejes3 = ”alfa beta”;s3 = s2;

TString& TString::operator=(const TString& s ) {

Page 93: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

class TString {public:

TString( TString&& s );};

Zdefiniujmy konstruktor przenoszący

Konstruktor przenoszący (mvc-tor): Możemy dopisać w main.cc

// obiekt źródłowy zostaje pozbawiony zasobów// ale pozostawiony w stanie do dalszego użytku czyli można coś np. do niego przypisać

s.ptr = nullptr;s.size = 0;

#ifdef DEBUGcout << "TString mvc-tor " << size << " - " << ( ptr ? ptr : "pusty" ) << endl;

#endif}

Operacja przenoszenia dzieje się automatycznie wtedy, gdy obiekt źródłowy „nie ma nazwy” i „nie ma adresu”

// move „maskuje” tożsamość obiektuTString s4 = std::move( s2 );// std::move będzie niepotrzebne// jeśli inicjalizować będzie obiekt// tymczasowy np. zwracany przez// funkcję jako wartość

TString::TString( TString&& s ) : ptr(s.ptr), size(s.size) {

Page 94: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

class TString { public:TString& operator=

( TString&& s );};

Zdefiniujmy operator przypisania przenoszący

Zdeklarujmy operator= przenoszący: Możemy dopisać w main.cc

if ( this != &s ) {delete [] ptr; // usuń dotychczasowy zasóbsize = s.size; // typy proste się tylko (po prostu) kopiujeptr = s.ptr; // tu zabieramy adres wskaźnika (przeniesienie praw własności)s.size = 0; // obiekt, któremu zabraliśmy, zerujemys.ptr = nullptr; // wskaźnik również zerujemy

}#ifdef DEBUG

cout << "TString move operator= " << size << " - " << ( ptr ? ptr : "pusty" ) << endl;#endifreturn *this; // nie zapomnij zwrócić obiektu!

}

// ponownie „ukrywamy obiekt”// za pomocą std::moves3 = std::move( s1 );

TString& TString::operator=( TString&& s ) {

Page 95: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Konwersja typów – konstruktor konwersji

• definiujemy konstruktor, który ma jeden argument – obiekt (lub referencję) innego typu, za jego pomocą kompilator dokona automatyczną konwersję typów

• klasa docelowa jest odpowiedzialna za konwersję typów

class A { /* … */ };class B { public:B(const A&) { /* … */ }

};void fun(B argb);// gdzieś w programie:A obiektA;fun(obiektA); // wymagany obiekt klasy B// kompilator wie jak przekonwertować B na AB obiektB = obiektA // zaskakujące?// działa (cc-tor klasy B) c-tor konwersji A na B

Page 96: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Konwersja typów – operator konwersji

• słowo operator, poprzedzające nazwę typu, do którego ma zostać dokonana konwersja (przeciążanie operatora)

• klasa źródłowa jest odpowiedzialna za konwersję typów

• tylko tak można zdefiniować konwersję z typów abstrakcyjnych do typów wbudowanych

class A { public: float r, s;char* nazwa;const char* cNazwa;A(float f1 = 1.0, float f2 = 3.14);operator B() const { return B(r); }operator char*() const { return nazwa; }operator const char*() const { returnc Nazwa;}

};class B { // …B(int n);

};void fun(B argb);// gdzieś w programie:A obiektA;fun(obiektA); // działa operator konwersji fun(22); // działa konstruktor klasy B

Page 97: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Konwersja typów – explicit

Konstruktor konwersji:• Jeśli nie chcemy niejawnego (automatycznego) konwertowania,

należy deklarację konstruktora poprzedzić słowem kluczowymexplicit B(const A&);

• Wtedy można tylko jawnie:fun(B(obiektA));obiektB = B(obiektA);

Operator konwersji: (C++11 – tylko w nowym standardzie)• Jeśli nie chcemy niejawnego (automatycznego) konwertowania,

należy deklarację operatora poprzedzić słowem kluczowymexplicit operator A();

• Wtedy można tylko jawnie:obiektB = B(obiektA); albo obiektB = (B)obiektA;albo obiektB = static_cast<B>( obiektA );

Page 98: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Konwersja typów – konflikty

class A {public:A(const B);

};class B {

public:operator A() const;

};void fun(A a);// gdzieś w programie:B b;fun(b); // niejednoznaczność

• Należy się zdecydować na jeden sposób konwersji• Konwersja jest jednostopniowa (tzn. jeśli mamy zdefiniowane B→A

i C→B, to jeśli na rzecz argumentu typu C zostanie podany argument typu A, nie nastąpi łańcuch konwersji od C do A

• Najpierw sprawdzana jest dwuznaczność, potem kontrola dostępu

"przeciążenie wyjścia"

class A { /* … */ };class B { /* … */ };class C {public:operator A() const;operator B() const;

};// tu się zaczyna problem// przeładowane wersje funvoid fun(A a);void fun(B b);// gdzieś w programie:C c;fun(c); // niejednoznaczność

Page 99: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

dziedziczenie [ inheritance ]

• technika definiowania nowej klasy z wykorzystaniem już istniejącej• klucz do tworzenia relacji dziedziczenia to określenie wspólnego zachowania klas• nie potrzebujemy kodu źródłowego, tylko plik nagłówkowy – możemy np. dziedziczyć z klas

bibliotecznych (które potem linkujemy)

class B : public A { /* ... */ };lista pochodzenia

A – klasa podstawowa (bazowa)B – klasa pochodna klasy A

klasa pochodna• dziedziczy wszystkie składniki klasy podstawowej (atrybuty i zachowanie)• można w niej zdefiniować

– dodatkowe dane składowe– dodatkowe funkcje składowe

• można w niej przedefiniować– składniki / funkcje już istniejące w klasie podstawowej– redefiniowany składnik zasłania składnik z klasy podstawowej

Page 100: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

• relacja: jest – czymś• relacja: uogólnienie – uszczegółowienie

( klasa bazowa – klasa pochodna )• klasa pochodna może

– rozszerzać możliwości klasy bazowej (implementacja nowych metod)– uściślać (ponowna implementacja metod istniejących w klasie bazowej)

Klasa pochodna zawsze może być traktowanajako klasa bazowa (w dziedziczeniu publicznym), oznacza to, że:

– można wskaźnikiem (referencją) klasy bazowej pokazywać na obiekty klaspochodnych i nie jest to operacja powodująca utratę części wskazywanegoobiektu

– dziedziczenie prywatne nie jest prawdziwym dziedziczeniem

relacja dziedziczenia – znaczenie

Page 101: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

klasa bazowa A klasa pochodna Bprivateprotected protectedpublic public

klasa bazowa A klasa pochodna Bprivateprotected protectedpublic

klasa bazowa A klasa pochodna Bprivate privateprotectedpublic

• dostęp do części prywatnej klasy bazowej A tylko przez jej interfejs

• mamy dostęp do części public i protectedz tym że protected na zewnątrz niedostępny(tak samo jak private)

public

protected

private • domyślny, niepodanie specyfikacjioznacza dziedziczenie privateclass B : A { /* ... */ };

• stosujemy gdy chcemy ukryć fakt dziedziczenia

dziedziczenie implementacji

dziedziczenie interfejsu

sposoby dziedziczenia (public, protected, private)

Page 102: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

• umożliwia selektywne zachowanie sposobu dziedziczenia składowych• należy umieścić w wybranej części klasy pochodnej

using klasa_podstawowa::nazwa_skladnika;można również według starego przepisu (bez słowa using)

klasa_podstawowa::nazwa_skladnika;• za pomocą using można zachować (powtórzyć) zakres dostępu

z klasy bazowej lub zmienić z protected na public (i vice versa)class A {// niedostępne w klasie pochodnej

int n; void getVal(int);

protected:int k;int calc();

public:int calc(int);void getVal();

};

class B : private A {protected:using A::k;using A::calc; // nie rozróżnia nazw przeciążonych

public:using A::getVal; // nie zadziała bo getVal jest też

}; // w części private• deklaracja dostępu nie może posłużyć do odsłonięcia

nazwy zasłoniętej w klasie pochodnej, również w przypadku redefinicji funkcji (wirtualnej)

• nie usuwa ew. wieloznaczności w dziedziczeniuwielokrotnym (najpierw zawsze jest rozstrzyganawieloznaczność)

deklaracja dostępu (using)

Page 103: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

• klasa B jest dla klasy C klasą podstawową bezpośrednią, zaśklasa A – klasą podstawową pośrednią

• inicjalizowanie klasy podstawowej poprzez wywołanie jejkonstruktora

C::C(int i, float f) : B(i,f) { // ...B::B(int i, float f) : A(i) { // ...

lista inicjatorów konstruktora• wywołujemy tylko konstruktor bezpośredniej klasy podstawowej• jeśli tego nie zrobimy, użyty będzie konstruktor domyślny, kolejność

jest “od góry” (klasa A), “do dołu” (klasa C)• gwarantowane jest też wywołanie destruktorów, w kolejności

odwrotnej (czyli od C do A)

A

B

C

dziedziczenie kilkupokoleniowe i inicjalizacja

Page 104: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

// wcześniej definiujemy klasy: MW, MX, MY, MZ oraz klasę Aclass B : public A {

MY my;MX mx;

public:B(int i) : mx(), my(), A() { /*...*/ }~B();

};class C : public B {

MW mw;MZ mz;

public:C() : mw(3.14), B(45) { /*...*/ }~C();

};

• kolejność wywołania konstruktorówelementów składowych jest związanaz kolejnością ich wystąpieniaw definicji klasy, a nie z kolejnościąna liście inicjatorów

• w przykładzie po lewej, kolejność konstrukcji:A, MY, MX, B, MW, MZ, C

• kolejność destrukcjijest dokładnie odwrotna:C, MZ, MW, B, MX, MY, A

kompozycja i dziedziczenie

Page 105: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

• przedefiniowanie (redefining) w przypadkuzwykłych funkcji składowych klasy bazowej

• zasłanianie (overriding) w przypadku funkcji wirtualnych klasy bazowejclass A { public:int fun() const;int fun(float) const;

};class B : public A { public:int fun() const; // przedefiniowanie

};class C : public A { public:void fun() const; // zmiana zwracanego typu

};class D : public A { public:int fun(char*) const; // zmiana listy argumentów

};

we wszystkich przypadkachniewidoczne (zasłonięte) stają się również funkcjeprzeciążone w klasie bazowej,tzn. tutaj: int fun(float) const;

gdyby w klasie A była metoda prywatna, to dostępu do niej nie mamy w klasach pochodnych, ale możemy ją przedefiniować !!! tak, że będzie działać nasza nowa wersja, tak jakby była tą funkcją składową z części prywatnej A

ukrywanie nazw w klasach pochodnych

Page 106: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

class A { public:A(const A& a);

};class B : public A { public:

B(const B& b) : A(b) { /* ... */ }};

• konstruktory (patrz C++11)

• operator=• destruktorKONSTRUKTOR KOPIUJĄCY• ten generowany automatycznie wykorzysta konstruktory kopiujące klas-przodków i

składników– chyba że któryś z tych konstruktorów kopiujących jest prywatny– uwaga: definicja jakiegokolwiek konstruktora (np. właśnie kopiującego) wyklucza

automatyczne generowanie zwykłego konstruktora• definiowany przez nas może je wywołać

• trzeba je zdefiniować samemu(lub zostaną wygenerowane automatycznie!)

• można jednak we własnych definicjach wywołać wersjez klas podstawowych do obsłużenia odziedziczonej części obiektu

jawne wywołanie konstruktorakopiującego klasy A, inaczej zostałbywywołany zwykły konstruktordomyślny klasy A

czego się nie dziedziczy (C++98)

Page 107: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

dziedziczenie konstruktorów ( C++11 )

Deklaracja using może być użyta z konstruktorami klasy bazowej

Dziedziczone konstruktory zachowują swoją specyfikację (tzn. są np. explicit lub są wyrażeniem stałym constexpr).

class Foo { public:explicit Foo(int); // explicit jako przykład „dobrego stylu”void fun();

};class Bar : public Foo { public:

using Foo::fun; // tu nic nowego, w zasadzie niepotrzebneusing Foo::Foo; // powoduje niejawną deklarację Bar::Bar(int); // taki konstruktor zdefiniowany/wygenerowany tylko w przypadku użyciavoid fun(); // nadpisuje Foo::fun() Bar( int, int ); // tu już samemu napisany konstruktor, bez dziedziczenia

};Bar b1( 7 ); // ok w C++11 dzięki dziedziczeniu konstruktoraBar b2( 3, 5 ); // normalne wywołanie Bar::Bar(int, int);

Page 108: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

dziedziczenie konstruktorów – dostępność, inicjalizacja składników ( C++11 )

Może się okazać, że odziedzczony konstruktor jest prywatny

Jeśli klasa potomna ma jeszcze jakieś składowe, to użycie dziedziczonego konstruktora jest ryzykowne. Składowe klasy Bar będą albo domyślnie inicjalizowane (s) albo niezainicjalizowane (x, y).Oczywiście można:

class Foo { private:explicit Foo(int);

};class Bar : public Foo { public:

using Foo::Foo; private:

string s;int x, y;

};Bar b1( 7 ); // błąd – woła Bar(int), który woła Foo(int), a ten jest niedostępny

błąd objawia sięw momencie próby użycia

string s = ”niezainicjalizowany”;int x = 0, y = 0;

Page 109: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

OPERATOR PRZYPISANIA operator=• ten generowany automatycznie wywoła operatory= klasy-przodka i

składników– chyba, że któryś z tych operatorów jest prywatny– chyba, że są składniki const lub składniki będące referencją – bo te

wymagają inicjalizacji• definiując operator= możemy je użyć

class A { public:A& operator=(const A& a);

};class B : public A { public:

B& operator=(const B& b) {A::operator=(b);// ...return *this; }

};

musi być podany zakres ( A:: )ponieważ nowodefiniowanyB::operator= przesłania funkcjęoperatora klasy bazowej

alternatywnie mozna tak:(*this).A::operator=(b);lubA *wsk = this; // możemy wskaźnikiem klasy bazowej(*wsk) = b; // pokazać na obiekt pochodnylubA &ref = *this; // możemy referencji do klasy bazowejref = b; // przypisać obiekt klasy pochodnej

czego się nie dziedziczy

Page 110: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

• składniki statyczne i oczywiście definiujemy je dla klasyw której są zdeklarowane– możemy je zasłaniać

class A { public:static int ca;static int getNew() { return ca; }

};class B : public A { public:

static int ca;static int getNew() { return ca; } // zasłania funkcję z klasy Astatic int getOld() { return A::ca; } // tak możemy się dostać do “starej” wartości

};int A::ca = 2;int B::ca = 5; // z powodu re-deklaracji w klasie B, musimy zdefiniować

• statyczne funkcje składowe– gdy przedefiniowane – zasłaniają funkcje z klasy podstawowej (wszystkie

przeciążone wersje), również wtedy gdy następuje zmiana sygnaturyfunkcji

co jest dziedziczone i warto wspomnieć

Page 111: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

• operatory konwersji typów – bo w klasach pochodnych mamy kompletinformacji do wykonania konwersji

• konstruktory konwersji nie są dziedziczone, ale…

class C { public:C(int n) : c(n) {}int c;

};

class A { public:A(int n) : a(n) {}A (const C& c) : a(c.c) {}int a;

};

void fun(const A& a) { cout << "a.a = " << a.a << endl; }void fun2(const B& b) { cout << "b.a = " << b.a << endl; }

int main() {C c(11);D d(22);A a(33);B b(44);fun(c); // normalnie, wypisze 11 – konwersja typufun(b); // co wypisze? 44 czy 46?fun(d); // co wypisze? 22 czy 25? fun2(c); // błąd – bo konstr. konwersji się nie dziedziczy

}

obiekt klasy B pokazywany referencją do klasy bazowej Ajest widziany jako obiekt klasy A,więc wypisana jest częśćobiektu z klasy A (tu zasłoniętaw klasie B)

class D : public C { public:D(int n) : C(n+3), c(n) {}int c;

};

class B : public A { public:B(int n) : A(n+2), a(n) {}int a;

};

obiekt klasy D jest również obiektem typu klasy C, więc możliwa jest konwersja obiektutypu D na obiekt typu A, wypisanajest ta część obiektu z klasy C(tu zasłonięta w klasie D)

co jeszcze jest dziedziczone

Page 112: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

• jest bezpieczne bo od typu bardziej wyspecjalizowanego przechodzimy do typu bardziej ogólnego

• jest naturalne: wskaźnikiem (referencją) typu bazowego pokazujemy na typ pochodny

class A { public: int a; };class B : public A { public: int b; };// gdzieś w programie…B b;A *wskA = &b;A &refA = b;

– poprzez wskA i refA oczywiście nie mamy dostępu do części zdefiniowanej w klasie B (tzn. intb), ale np. poprzez jawne rzutowanie (w dół !) można się tam dostać

• co jeśli przez wartość?A a = b;

– to też dopuszczalne, ale następuje nieodwracalna strata części obiektu klasy B(tu zadziała konstruktor kopiujący z klasy A, który nic nie wie o dodatkowej części z klasy B)

rzutowanie w górę (upcasting) i w dół

Page 113: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

class A { public: void getMe() { cout << "Jestem A/n"; }

};class B : public A { public:

void getMe() { cout << "Jestem B/n"; } };class C : public B { public:

void getMe() { cout << "Jestem C/n"; } };// …gdzieś w programieB b;C c;A *ptrA = &b;A &refA = c;A a = b;ptrA->getMe(); // "Jestem A"refA.getMe(); // "Jestem A"a.getMe(); // "Jestem A"

to nas nie zadowala, boprzecież pokazywane sąobiekty klas pochodnych

chcielibyśmy, żeby wskaźnik(referencja) inteligentniereagowały na typ obiektuna który pokazują, wołającjego funkcję…

polimorfizm – czego oczekujemy?

Page 114: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

class A { public: virtual void getMe() { cout << "Jestem A/n"; }

};class B : public A { public:

void getMe() { cout << "Jestem B/n"; } };class C : public B { public:

void getMe() { cout << "Jestem C/n"; } };// …gdzieś w programieB b;C c;A *ptrA = &b;A &refA = c;A a = b;ptrA->getMe(); // "Jestem B"refA.getMe(); // "Jestem C"a.getMe(); // "Jestem A" – nieodwracalne "przycięcie" do A

w klasie bazowej (tutaj klasie A)

musimy w deklaracjifunkcji dodać

virtual

funkcja getMe() jest wirtualna w każdejklasie pochodnej, można (ale nie trzebabo jest to mylące) dopisać "virtual"również w klasie B i C…

• ściśle rzecz biorąc polimorficzne jestwywołanie funkcji, a nie funkcja• klasa, w której jest zdefiniowana lub odziedziczona funkcja wirtualna,nazywa się klasą polimorficzną

polimorfizm - rozwiązanie

Page 115: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

• funkcja globalna nie może być wirtualna (bo przecież polimorficzne orientowanie ze względu na typ obiektu…)

• funkcja wirtualna nie może być statyczna• funkcja wirtualna może być przyjacielem jakiejś innej klasy, ale tylko konkretna realizacja funkcji wirtualnej

z danej klasy jest tym przyjacielem (a nie wszystkie funkcje) bo przyjaźni się nie dziedziczy• w klasie pochodnej można zasłonić funkcję wirtualną z klasy bazowej (definicja obiektu lub innej funkcji o tej

samej nazwie), ale w kolejnej klasie pochodnej (do klasy pochodnej) można ją znów zdefiniować i korzystać z polimorfizmu

• jeśli zmienia się zakres dostępu dla funkcji wirtualnej, np. w klasie bazowej funkcja ta była public, a w klasie pochodnej jest protected lub private

sposób dostępu taki jak w typie użytego wskaźnika lub referencjiclass A { public:

virtual void f() { cout << "Jestem A" << endl; }};class B : public A { private:

void f() { cout << "Jestem B" << endl; }};int main(){

A *ptrA = new B;ptrA->f(); // "Jestem B"B &refB = dynamic_cast<B&>(*ptrA);refB.f(); // błąd - virtual void B::f() is private

}

dostęp rozstrzyganyna poziomie wiedzy wyniesionej z klasybazowej A, bo pokazujemywskaźnikiem klasy bazowej

funkcje wirtualne – kilka szczegółów

Page 116: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

• konstruktory nie są dziedziczone (C++98), nie mogą być wirtualne– żeby zadziałał polimorfizm to musi być pokazywany obiekt

danego typu (wskaźnikiem, referencją), a tego obiektu "jeszcze nie ma", jest konstruowany

• destruktor – nie jest dziedziczony, ale tak!Jeśli klasa posiada choć jedną deklarację funkcji jako virtual, jej destruktor też deklarujmy jako virtual

– wtedy destruktory klas pochodnych też będą virtual– działać będzie polimorfizm i poprawna destrukcja obiektu

konstruktor, destruktor – wirtualny

Page 117: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

• tworzona po to, aby być klasą bazową do dziedziczenia• będziemy korzystać z polimorfizmu (virtual)• implementacja metod niepotrzebna, deklaracja interfejsu

virtual void funkcja() = 0; // czysto wirtualna– ta wersja funkcji nigdy nie ma być wykonana, konieczność implementacji

(uściślenia) w klasie pochodnej– klasa jest abstrakcyjna gdy ma choć jedną funkcję wirtualną– dziedziczona jako czysto wirtualna, więc jeśli nie ma jej definicji w klasie

pochodnej, klasa pochodna też jest klasą abstrakcyjną– nie można stworzyć żadnego obiektu klasy abstrakcyjnej– funkcja nie może zwracać przez wartość obiektu klasy abstrakcyjnej– nie może być typem w jawnej konwersji

FUNKCJE WIRTUALNE i ich ciałavirtual void funkcja() { } // zwykła, musi mieć definicjęvirtual void funkcja() = 0; // pure virtual, bez definicji ► może mieć definicję, umieszcza się ją poza ciałem klasy→ taką funkcję można wywołać tylko wprost (z operatorem zakresu) czyli klasa::funkcja() lub

z wnętrza konstruktora (destruktora) klasy, w której jest ona czysto wirtualna→ niezdefiniowanie ciała funkcji "pure virtual" w którejś z kolejnych klas pochodnych, czyni z tej

klasy pochodnej znowu klasę abstrakcyjną

dziedziczenie – klasa abstrakcyjna

Page 118: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

TOsoba

nazwiskoadresdata urodzenia

TStudent

statuswydziałkursy

TNauczyciel

funkcjakursy

TDoktorantnie może się zapisywaćna kursy podstawowe

TOsoba

nazwiskoadresdata urodzenia

TStudent

statuswydziałkursy

TNauczyciel

funkcjakursy prowadzone

TDoktorant

TDoktorantNaucz

doktorant z obowiązkiemprowadzenia zajęć

dydaktycznych

TOsoba

nazwiskoadresdata urodzenia

wielokrotne dziedziczenie spowodujezapewne pojawienie się konfliktu niejednoznaczności, np. funkcja print() odziedziczona podwójnie…

dziedziczenie kontra zawieranie – przykład uniwersytecki

Page 119: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

class TDoktorantNaucz {private:TNauczyciel nauczycielProxy;TDoktorant doktorantProxy;

// sporo kodu do napisania};

• funkcje składowe implementacji klasy TDoktorantNaucz muszą wywoływać odpowiednie funkcje obiektów pomocniczych nauczycielProxy i doktorantProxy

• mamy podwójne obiekty klasy TOsoba, więc trzeba zapewnić poprawne zarządzanie stanem gdy zmieniane są dane TOsoba, taka niespójność jest uciążliwa

• zalety to lepsza hermetyzacja, implementator może udostępnić jedynie te funkcje, których klient powinien używać

TNauczyciel

TDoktorant

TDoktorantNaucz

1

1

dziedziczenie wielokrotne – alternatywa 1

Page 120: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

class TDoktorantNaucz : public TDoktorant {

private:TNauczyciel nauczycielProxy;

// trochę kodu do napisania};

• TDoktorantNaucz dziedziczy wszystkie cechy klasy TDoktorant, a pośrednio również TStudent i TOsoba, trzeba zaś napisać funkcje, które wiążą się z klasą TNauczyciel

• nadal istnieje problem podwójnego obiektu klasy TOsoba, ale łatwiej nim zarządzać, korzystać z odziedziczonego po klasie TDoktorant, a kontrolując dostęp do TNauczyciel nie używać danych TOsoba z nim związanych

TDoktorant

TNauczycielTDoktorantNaucz1

dziedziczenie i zawieranie – alternatywa 2

Page 121: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

• wszystkie wirtualne klasy bazowe inicjalizuje się w konstruktorze ostatniej klasy pochodnej, czyli konstruktor klasy TOsoba trzeba wywołać przy tworzeniu obiektu klasy TDoktorantNaucz, jest to niewygodne

• jeśli konstruktor ostatniej klasy pochodnej nie wywołuje jawnie konstruktora wirtualnej klasy bazowej, kompilator próbuje wywołać domyślny konstruktor wirtualnej klasy bazowej

• łatwiej pisać kod, gdy wirtualna klasa bazowa posiada konstruktor domyślny, ale w naszym przypadku to nie ma sensu (nie ma przecież "domyślnego" nazwiska etc.)

TOsoba

nazwiskoadresdata urodzenia

TStudent

statuswydziałkursy

TNauczyciel

funkcjakursy prowadzone

TDoktorant

TDoktorantNaucz

wirtualnaklasabazowa

dziedziczenie wielokrotne – alternatywa 3

Page 122: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

TOsoba

nazwiskoadresdata urodzenia

TStudent

statuswydziałkursy

TNauczyciel

funkcjakursy prowadzone

TDoktorant

TDoktorantNaucz

wirtualnaklasabazowa

istnienie konstruktora w klasie (np. domyślnego)zależy wyłącznie od projektu interfejsu, nie należydodawać funkcji składowych tylko po to, aby uniknąć błędów kompilacji

TDoktorantNaucz

TOsoba

TNauczyciel

TDoktorant

TStudent

dziedziczenie wielokrotne - koszty

Page 123: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

• chcemy dodać do naszej "abstrakcji uniwersytetu" asystenta badań, nie musi on być studentem i nie musi prowadzić zajęć dydaktycznych

• co jednak zrobić jeśli TDoktorant podejmie pracę jako TAsystentBadan, nawet na innym wydziale?

• problem wynika stąd, że "prowadzenie badań" to właściwość jaką może nabyć każda osoba, nie tylko student lub wykładowca

• w wyniku złożoności relacji zachodzi tu konflikt wymagań, którego nie da się rozwiązać za pomocą dziedziczenia

• dziedziczenie jest odpowiednim mechanizmem do modelowania tych relacji między klasami, które zawsze są spełnione

TOsoba{ virtual }

TStudent TNauczyciel

TDoktorant

TDoktorantNaucz

TAsystentBadan

• dziedziczenie jest relacjąstatyczną - trudno ją zmienić• kiedy relacje między klasamizmieniają się, przydatność dziedziczenia jest ograniczona• relacje w hierarchii dziedziczeniasą określone i zakodowane na stałe

dziedziczenie – statyczna relacja

Page 124: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

• chcemy dodać możliwość zostania studentem za pomocą klasy mieszanej MozeBycStudentem

• klasa ta dodaje metody potrzebne do zapisania się na kursy oraz do identyfikacji studenta

enum EWyksztalcenie { ePodstawowe, eSrednie, eLicencjat, eMagister, eDoktor };

clas MozeBycStudentem { public:void setWydzial( EWydzial dep );EWydzial getWydzial() const;virtual bool zapiszNaKurs( const TKurs& ) = 0;virtual bool usunZKursu( const TKurs& ) = 0;virtual void pokazKursy() const = 0;virtual EWyksztalcenie getWyksztalcenie() const;// więcej kodu

};• w klasie TStudent trzeba zaimplementować

wszystkie wirtualne metody dziedziczone po MozeBycStudentem, w której można też zdefiniować jakąś domyślną implementację

TOsoba

TStudent

MozeBycStudentem

• klasa mieszana pozwala na dodanie nowych możliwości do innych klas• nie tworzymy egzemplarza klasy mieszanej (nie ma to sensu)• użycie klas pozwala łączyć różne możliwości w nowe jednostki• klasy mieszane reprezentują statyczne relacje, nowe własności można dodać w trakcie projektowania hierarchii, nie zaś dynamicznie w trakcie wykonywania programu

klasa mieszana – mix-in-class

Page 125: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

• klasa TOsoba nie musi już być wirtualną klasą bazową, co upraszcza zarządzanie kodem

• elastyczność i prostotę projektu uzyskuje się dzięki rozłożeniu możliwości na kilka klas

• w hierarchii z użyciem klas mieszanych można dodawać nowe możliwości bez wpływu na inne klasy w hierarchii

TOsoba

TStudent

MozeBycStudentemMozeNauczacMozeWykBadania

TNauczyciel

TAsystentBadan

TDoktorant

TDoktorantNaucz

TDoktorantBadacz

Dodajemy dalszą funkcjonalność za pomocą klas mieszanych, to znaczy klasę reprezentującą osoby z kwalifikacjami do prowadzenia kursów MozeNauczac oraz do prowadzenia badań MozeWykBadania

Kiedy klasy mieszane?1. istnieje wiele

niezależnych właściwości, które klasa może posiadać

2. trzeba wybiórczo dodać nową własność do niektórych klas w istniejącej hierarchii

klasy mieszane - dyskusja

Page 126: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

• kiedy student kończy studia i staje się doktorantem, zmiany w obiekcie powinny dotyczyć jedynie tych części, które rzeczywiście ulegają zmianie, czyli powinna istnieć możliwość dodania do obiektu TStudent części TDoktorant

• jeśli TDoktorant staje się obiektem TNauczyciel, możliwości klasy TDoktorant powinny zostać zmienione przez możliwości klasy TNauczyciel

Wiemy już, że należy unikać niepotrzebnego powielania danych (wirtualne klasy bazowe) - bo powoduje to utratę zasobów i problemy z zarządzaniem tymi danymiWarto też do minimum ograniczyć ilość kopiowanych danych kiedy przekształcamy lub kopiujemy obiekt

Jak przekształcić TStudent w TDoktorant? • trzeba utworzyć nowy obiekt

TDoktorant i zainicjalizować go (skopiować dane) z obiektu TStudent

• ponosimy tu niepotrzebne koszty kopiowania części TOsoba, która się przecież nie zmieniaWidzimy brak elastyczności dziedziczenia

wielokrotnego w dynamicznie zmieniających sięsytuacjach - często ma miejsce w bazach danych

dynamiczna zmiana sytuacji – czyli co po studiach?

• a co jeśli osoba jest doktorantem na jednym wydziale i równocześnie asystentem badań na innym? - do zarządzania potrzeba wtedy dwóch niezależnych obiektów TDoktorant oraz TAsystentBadan, a w obu powtarzają się dane części TOsoba

• a co jeśli osoba studiuje dwa kierunki?

Page 127: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

TOsoba

TStudent

TCzlonekUniwersytetu

TNauczyciel TBadacz

TDoktorant

0 .. n

do kogo

pełni rolęDana osoba może pełnić wiele ról, ale w konkretnym momencie pełni tylko jedną rolęKażda osoba posiada n ról jako członka uniwersytetuKażda rola należy tylko do jednej osoby (relacja "do kogo")Od każdego obiektu TCzlonekUniwersytetu można uzyskać informację o tym do kogo należy dana rolaObiekt TOsoba przechowuje listę wszystkich możliwych ról pełnionych przez daną osobę – nie powiela się danych osobowychRole są oddzielone od osoby, która je pełni, role tworzą odrębną hierarchię –do każdej osoby można przypisać dowolną liczbę ról, nawet tę samą rolę dwa razy (np. student dwóch kierunków)

Implementacja – problem określania typu• Klasy TStudent, TNauczyciel, TBadacz posiadają

różne metody ale wspólną klasę bazową TCzlonekUniwersytetu. Obiekt TOsoba zwraca za pomocą metody aktualną rolę danej osoby – ale jest to obiekt typu TCzlonekUniwersytetu

• Polimorficzne używanie obiektów tej klasy bazowej może nie być zbyt użyteczne, ponieważ nie jest możliwe uchwycenie we wspólny interfejs zachowania wszystkich klas pochodnych

• Konieczne jest poznanie rzeczywistego typu obiektu, czyli użycie mechanizmu RTTI (elastyczność kosztem złożoności kodu)

dynamiczna zmiana sytuacji – role

Page 128: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Niepotrzebne stają się klasy złożone, typu TDoktorantBadacz, ponieważ osobie można przypisać rolę badacza oraz rolę nauczyciela (w danej chwili pełniona jest tylko jedna z nich)

Dostęp do danych TOsoba jest teraz możliwy tylko przez metody klasy TCzlonekUniwersytetu

Obiekt TCzlonekUniwersytetu nie zależy od osoby, ale zawiera informacje potrzebne osobie do pełnienia danej roli

Można więc powiązać konkretną rolę z wieloma osobami – można np. utworzyć grupę osób prowadzących te same badania, czyli pełniących taką samą rolę…

Dwie osoby mogą prowadzić taki sam wykład (rola wykładowcy), sześć osób może prowadzić takie same ćwiczenia…

Role są przenośne

role i ich konsekwencje

Page 129: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Problem – gdy potrzeba wiele kombinacji różnych klas, może dojść do eksplozji kombinatorycznej

• Hierarchie dziedziczenia wielokrotnego są trudniejsze do zrozumienia od hierarchii dziedziczenia jednokrotnego, dodanie wirtualnych klas bazowych komplikuje jeszcze bardziej

TOsoba

TStudent

MozeBycStudentemMozeNauczacMozeWykBadania

TNauczyciel

TAsystentBadan

TDoktorant

TDoktorantNaucz

TDoktorantBadacz

TStudentBadacz TNauczycielDoksztalc

Klasy mieszane dodają statyczne możliwości (decyzję trzeba podjąć podczas projektowania hierarchii klas)Utworzony obiekt może odpowiadać na komunikaty będące zawarte w klasie bazowej (klasach bazowych)Klasy mieszane łatwe do zrozumienia i implementacji

Obiekty pełniące rolę to lepsze rozwiązanie w dynamicznie zmieniających się sytuacjach

Można utworzyć obiekt TOsoba bez żadnych ról, które przypisze się później

klasy mieszane vs pełnione role

Page 130: Język C++ ( Programowanie II ) Rok akademicki 2010/11it.pwsz-ns.edu.pl/~wprzygoda/JEZYK_CPP_2016.pdf · C++. Biblioteka standardowa. Podręcznik programisty Wydanie II po angielsku

Klasy mieszane dodają statyczne możliwości (decyzję trzeba podjąć podczas projektowania hierarchii klas)Utworzony obiekt może odpowiadać na komunikaty będące zawarte w klasie bazowej (klasach bazowych)Klasy mieszane łatwe do zrozumienia i implementacji

Obiekty pełniące rolę to lepsze rozwiązanie w dynamicznie zmieniających się sytuacjach

Można utworzyć obiekt TOsoba bez żadnych ról, które przypisze się później

Problem – zależność od mechanizmu RTTI lub podobnych, potrzeba napisania dodatkowego kodu do używania i konwersji obiektów TCzlonekUniwersytetu

• Klasy pochodne od klasy TCzlonekUniwersytetu trzeba określić w czasie kompilacji programu

Klasy mieszane a rolerole – lepsze gdy istnieje zbyt wiele możliwych kombinacji ról i kombinacje te mogą się zmieniać dynamicznieklasy mieszane – gdy kombinacja ról jest mała i jedna osoba może pełnić tylko jedną rolę danego rodzaju

klasy mieszane a role – przypadki zastosowań