Biblioteki i przestrzenie nazw

Slides:



Advertisements
Podobne prezentacje
C++ wykład 9 ( ) Szablony.
Advertisements

C++ wykład 2 ( ) Klasy i obiekty.
C++ wykład 4 ( ) Przeciążanie operatorów.
Programowanie obiektowe
Programowanie Wizualne WYKŁAD 4
Standardowa biblioteka języka C++
Programowanie obiektowe
Wzorce.
Język ANSI C Funkcje Wykład: Programowanie komputerów
Static, const, volatile.
Programowanie w środowisku sieciowym
PROGRAMOWANIE STRUKTURALNE
Informatyka Stosowana
formatowanie kodu źródłowego
Generator analizatorów składniowych
Kurs Pascala – spis treści
Struktury.
1 Dygresja: cztery płyty główne…. 2 Dygresja: osobliwości C /* cos o nieistniejacym typie Boolean */ /* oraz o operatorze przecinkowym */ #include int.
C++ wykład 2 ( ) Klasy i obiekty.
Wykład 1: Wskaźniki Podstawy programowania Programowanie w C
Opcje kompilatora g77 g77 [opcje] pliki_źródłowe Opcje: -c tylko kompilacja bez linkowania -S kompilacja do kodu assemblera -E tylko pre-processing -o.
Java – programowanie obiektowe
Tworzenie nowej biblioteki
Pakiety w Javie Łukasz Smyczyński (132834). Czym są pakiety? Klasy w Javie są grupowane w pewne zbiory zwane pakietami. Pakiety są więc pewnym podzbiorem.
Podstawy programowania II
Podstawy programowania
W SYSTEMIE OPERACYJNYM UNIX / LINUX
Podstawy programowania. Język C i C++– podstawy Temat: 1
Struktura programu w Turbo Pascalu.
Podstawy programowania II
Programowanie strukturalne i obiektowe
Automatyka i Robotyka Systemy czasu rzeczywistego Wykład 4.
Programowanie obiektowe – zastosowanie języka Java SE
5 Etapów Pracy Kompilatora
Andrzej Repak Nr albumu
Programowanie obiektowe Wykład 3 dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/21 Dariusz Wardowski.
Programowanie obiektowe Wykład 6 dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/14 Dariusz Wardowski.
Przeglądanie zasobów komputera - uruchamianie programów
Podstawy informatyki 2013/2014
Programowanie obiektowe – język C++
Programowanie obiektowe 2013/2014
Prasek Aneta, Skiba Katarzyna. Funkcje stałe const to takie funkcje, które nie mogą modyfikować stanu obiektu. Oznacza to, że funkcja stała nie może zmieniać.
Kurs języka C++ – wykład 3 ( )
Wykład 7 Synchronizacja procesów i wątków
Systemy operacyjne (wiosna 2014)
Programowanie w języku C++
Podstawy programowania
Programowanie strukturalne i obiektowe C++
C++.
Treści multimedialne - kodowanie, przetwarzanie, prezentacja Odtwarzanie treści multimedialnych Andrzej Majkowski informatyka +
Programowanie strukturalne i obiektowe C++
Model obiektowy bazy danych
Programowanie strukturalne i obiektowe C++
Biblioteka DLL w oparciu o źródła w języku C
Kurs języka C++ – wykład 4 ( )
Programowanie strukturalne i obiektowe C++ Powtórzenie wiadomości z C++ Robert Nowak.
Podstawy programowania
Dokumentacja programu komputerowego i etapy tworzenia programów.
Podstawy informatyki Preprocesor Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi.
Podstawy informatyki Funkcje Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi.
C++ WYKŁAD 12 ( ) Własne biblioteki. S PIS TREŚCI Kompilacja i łączenie Moduły Biblioteki Biblioteka statyczna Biblioteka współdzielona Biblioteka.
Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi i Pawła Jerzego Matuszyka Podstawy.
K URS JĘZYKA C++ – WYKŁAD 3 ( ) Przenoszenie Składowe statyczne Funkcje wbudowane Argumenty domyślne.
K URS JĘZYKA C++ – WYKŁAD 7 ( ) Konwersje.
C++ WYKŁAD 13 ( ) Algorytmy. S PIS TREŚCI Funktory i predykaty Funkcje lambda.
Programowanie strukturalne i obiektowe Klasa I. Podstawowe pojęcia dotyczące programowania 1. Problem 2. Algorytm 3. Komputer 4. Program komputerowy 5.
Programowanie Obiektowe – Wykład 6
Programowanie obiektowe – zastosowanie języka Java SE
Język C++ Typy Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi i Pawła Jerzego.
Zapis prezentacji:

Biblioteki i przestrzenie nazw C++ wykład 9 (11.04.2012) Biblioteki i przestrzenie nazw

Moduły Każdy większy program składa się z pewnej liczby oddzielnych części – modułów. Moduł to kompletny fragment programu (moduł obliczeniowy, moduł we/wy, moduł prezentacji, itp). Podział kodu na moduły porządkuje logikę programu. Należy minimalizować zależności między modułami.

Biblioteki Moduły, z których może korzystać wiele programów umieszcza się w oddzielnych skompilowanych plikach, zwanych bibliotekami. Typy bibliotek w C++: biblioteka statyczna jest dołączana do programu wynikowego na etapie linkowania; biblioteka współdzielona jest dołączana do programu w trakcie ładowania programu do pamięci; biblioteka dynamiczna jest dołączana do uruchomionego procesu w trakcie działania programu.

Biblioteki Biblioteka to zbiór klas, funkcji i zmiennych, z których mogą korzystać różne programy. Biblioteka ma postać binarną – jej poszczególne fragmenty są skompilowane (biblioteka jest kolekcją plików obiektowych). Korzystanie z bibliotek ułatwia programowanie (korzystamy z gotowych i sprawdzonych fragmentów kodu) i przyspiesza proces rekompilacji.

Biblioteki Wynikiem samej kompilacji pliku źródłowego (plik.c albo plik.cpp) jest plik plik.o pod Linuxem albo plik.obj pod Windowsem. Biblioteki statyczne mają nazwy libmodul.a pod Linuxem albo modul.lib pod Windowsem. Biblioteki dynamiczne mają nazwy libmodul.so pod Linuxem (tak jak biblioteki współdzielone) albo modul.dll pod Windowsem.

Biblioteka statyczna Używając biblioteki statycznej przekazujemy jej archiwum linkerowi w czasie kompilacji. Linker wyszukuje w nim tylko tych plików obiektowych, które są niezbędne do działania naszego programu i kopiuje je bezpośrednio do programu. Program wynikowy korzystający z biblioteki statycznej jest obszerniejszy ale szybciej się ładuje do pamięci. Program wynikowy zlinkowany z biblioteką statyczną jest niezależny od plików zewnętrznych. Uaktualnienie biblioteki wymaga rekompilacji programu.

Biblioteka statyczna lib.cpp g++ lib.o prog.cpp ar g++ static library prog.o linker g++ a.out loader ssh memory

Biblioteka współdzielona Programy korzystające biblioteki współdzielonej nie zawierają bezpośrednio kodu z tej biblioteki a tylko referencję do niej. Program wynikowy korzystający z biblioteki współdzielonej jest chudszy ale wolniej ładuje się do pamięci (biblioteki współdzielone są odszukiwane i ładowane do pamięci razem z programem). Program wynikowy skompilowany z biblioteką współdzieloną jest zależny od plików zewnętrznych. Zmodyfikowanie biblioteki współdzielonej spowoduje zmianę w działaniu programu ale bez jego ponownej kompilacji.

Biblioteka współdzielona prog.cpp g++ lib.cpp prog.o g++ lib.o linker g++ g++ shared library a.out loader ssh memory

Biblioteka dynamiczna Programy korzystające bibliotek dynamicznych nie zawierają bezpośrednio kodu z tej biblioteki ale muszą korzystać ze specjalnych metod włączania takich bibliotek w trakcie działania programu (plik nagłówkowy <dlfcn.h>). Program wynikowy korzystający z biblioteki dynamicznej jest chudszy i szybciej ładuje się do pamięci, ale działa wolniej (biblioteki dynamiczne można załadować w dowolnym momencie w trakcie działania programu). Program wynikowy skompilowany z biblioteką dynamiczną jest zależny od plików zewnętrznych. Zmodyfikowanie biblioteki dynamicznej spowoduje zmianę w działaniu programu ale bez jego ponownej kompilacji.

Biblioteka dynamiczna prog.cpp g++ prog.o lib.cpp linker g++ g++ lib.o a.out g++ dynamic library loader a.out ssh memory

Tworzenie bibliotek (pod Linuxem) Tworzenie programu bez dołączanych bibliotek. Załóżmy, że mamy pliki src1.cpp, src2.cpp i src3.cpp, które stanowią moduł obliczeniowy oraz plik prog.cpp, który będzie korzystał z funkcji i klas zdefiniowanych w module obliczeniowym. Aby skompilować cały program razem z modułem obliczeniowym należy wydać polecenie: $ g++ -Wall -ansi -pedantic src1.cpp src2.cpp src3.cpp prog.cpp -o calculation Aby skompilować cały program razem z modułem obliczeniowym i statycznie zlinkować z innymi bibliotekami (rozmiar programu wynikowego będzie znacznie większy) należy wydać polecenie: $ g++ -static … Aby uruchomić skompilowany program należy wydać polecenie: $ ./calculation Aby sprawdzić z jakimi bibliotekami jest linkowany program i jakie symbole są w nim użyte należy wydać polecenie: $ ldd calculation $ nm calculation

Tworzenie bibliotek (pod Linuxem) Program korzystający z biblioteki statycznej. Najpierw kompilujemy pliki źródłowe do plików obiektowych: $ g++ -c -Wall -ansi -pedantic src1.cpp src2.cpp src3.cpp Następnie łączymy pliki obiektowe do jednego pliku bibliotecznego libsrc.a: $ ar crs libsrc.a src1.o src2.o src3.o Na koniec należy skompilować plik z programem i zlinkować go z biblioteką: $ g++ -c -Wall -ansi -pedantic prog.cpp $ g++ -o calculation prog.o –L. –lsrc Teraz można uruchomić skompilowany program: $ ./calculation Wyjaśnienie: opcja -Lścieżka określa ścieżkę do biblioteki, opcja -lbiblioteka określa nazwę biblioteki.

Tworzenie bibliotek (pod Linuxem) Program korzystający z biblioteki współdzielonej. Najpierw kompilujemy pliki źródłowe z opcją -fpic do plików obiektowych: $ g++ -fpic –c -Wall -ansi -pedantic src1.cpp src2.cpp src3.cpp Następnie łączymy pliki obiektowe do jednego pliku bibliotecznego libsrc.so: $ g++ –fpic -shared -o libsrc.so src1.o src2.o src3.o Na koniec należy skompilować plik z programem i wlinkować do niego informacje o bibliotece: $ g++ -Wall -ansi -pedantic prog.cpp $ g++ -o calculation prog.o –L. –lsrc Przed uruchomieniem programu trzeba zapisać w zmiennej środowiskowej LD_LIBRARY_PATH ścieżkę do biblioteki: $ export LD_LIBRARY_PATH="LD_LIBRARY_PATH:ścieżka" Teraz można uruchomić skompilowany program: $ ./calculation

Tworzenie bibliotek (pod Linuxem) Program korzystający z biblioteki dynamicznej. Bibliotekę dynamiczną przygotowujemy tak samo jak bibliotekę współdzieloną libsrc.so: $ g++ -fpic –c -Wall -ansi -pedantic src1.cpp src2.cpp src3.cpp $ g++ –fpic -shared -o libsrc.so src1.o src2.o src3.o Na koniec należy skompilować plik z programem i dołączyć do niego dynamicznego linkera opcją -ldl: $ g++ -Wall -ansi -pedantic prog.cpp $ g++ -o calculation prog.o –ldl Teraz można uruchomić skompilowany program: $ ./calculation Wyjaśnienie: aby skorzystać z dynamicznego linkera należy do programu włączyć plik nagłówkowy <dlfcn.h>; aby załadować dynamiczną bibliotekę trzeba skorzystać z funkcji dlopen, dlsym, dlerror i dlclose.

Przestrzenie nazw Przestrzeń nazw to obszar, w którym umieszcza się różne deklaracje i definicje. Przestrzeń nazw definiuje zasięg, w którym dane nazwy będą obowiązywać i będą dostępne. Przestrzenie nazw rozwiązują problem kolizji nazw. Przestrzenie nazw wspierają modularność kodu.

Definicja przestrzeni nazw Przestrzeń nazw tworzymy za pomocą słowa kluczowego namespace, ograniczając zawartość klamrami: namespace przestrzeń { // deklaracje i definicje } Aby odnieść się do typu, funkcji albo obiektu umieszczonego w przestrzeni nazw musimy stosować kwalifikator zakresu przestrzeń:: poza tą przestrzenią. Funkcja main() musi być globalna, aby środowisko uruchomieniowe rozpoznało ją jako funkcję specjalną. Do nazw globalnych odnosimy się za pomocą pustego kwalifikatora zakresu ::, na przykład ::wspolczynnik. Jeśli w przestrzeni nazw zdefiniujemy klasę to do składowej statycznej w takiej klasie odnosimy się kwalifikując najpierw nazwą przestrzeni a potem nazwą klasy przestrzeń::klasa::składowa.

Definicja przestrzeni nazw Przykład przestrzeni nazw: namespace wybory { int min2 (int, int); int min3 (int, int, int); } int wybory::min2 (int a, int b) { return a<b ? a : b; } int wybory::min3 (int a , int b , int c) { return min2(min2(a,b),c); } int min4 (int a, int, b, int c, int d) { return wybory::min2( wybory::min2(a,b), wybory::min2(c,d)); }

Deklaracja użycia Deklaracja użycia wprowadza lokalny synonim nazwy z innej przestrzeni nazw (wskazanej nazwy można wówczas używać bez kwalifikowania jej nazwą przestrzeni). Deklaracja użycia using ma postać: using przestrzeń::symbol; Deklaracja użycia obowiązuje do końca bloku, w którym wystąpiła. Deklaracje użycia stosujemy w celu poprawienia czytelności kodu. Deklaracje użycia należy stosować tak lokalnie, jak to jest możliwe. Jeśli większość funkcji w danej przestrzeni nazw korzysta z jakiejś nazwy z innej przestrzeni, to deklaracje użycia można włączyć do przestrzeni nazw.

Dyrektywa użycia Dyrektywa użycia udostępnia wszystkie nazwy z określonej przestrzeni nazw. Dyrektywa użycia using namespace ma postać: using namespace przestrzeń; Dyrektywy użycia stosuje się najczęściej w funkcjach, w których korzysta się z wielu symboli z innej niż ta funkcja przestrzeni nazw. Globalne dyrektywy użycia są stosowane do transformacji kodu i nie powinno się ich stosować do innych celów. Globalne dyrektywy użycia w pojedynczych jednostkach translacji (w plikach .cpp) są dopuszczalne w programach testowych czy w przykładach, ale w produkcyjnym kodzie jest to niestosowne i jest uważane za błąd. Globalnych dyrektyw użycia nie wolno stosować w plikach nagłówkowych!

Anonimowe przestrzenie nazw Anonimową przestrzeń nazw tworzymy za pomocą słowa kluczowego namespace bez nazwy, ograniczając zawartość klamrami: namespace { // deklaracje i definicje } Anonimowa przestrzeń nazw zastępuje użycie deklaratora static przy nazwie globalnej – dostęp do nazw zdefiniowanych w przestrzeni anonimowej jest ograniczony do bieżącego pliku. Dostęp do anonimowej przestrzeni nazw jest możliwy dzięki niejawnej dyrektywie użycia. namespace $$$ { // deklaracje i definicje } using namespace $$$; W anonimowej przestrzeni nazw $$$ jest unikatową nazwą w zasięgu, w którym jest zdefiniowana ta przestrzeń.

Przeszukiwanie nazw Gdy definiujemy funkcję z jakiejś przestrzeni nazw (przed nazwą definiowanej właśnie funkcji stoi kwalifikator przestrzeni) to w jej wnętrzu dostępne są wszystkie nazwy z tej przestrzeni. Funkcja z argumentem typu T jest najczęściej zdefiniowana w tej samej przestrzeni nazw co T. Jeżeli więc nie można znaleźć funkcji w kontekście, w którym się jej używa, to szuka się jej w przestrzeniach nazw jej argumentów. Jeżeli funkcję wywołuje metoda klasy K, to pierwszeństwo przed funkcjami znalezionymi przez typy argumentów mają metody z klasy K i jej klas bazowych.

Aliasy przestrzeni nazw Jeżeli użytkownicy nadają przestrzeniom nazw krótkie nazwy, to mogą one spowodować konflikt. Długie nazwy są niewygodne w użyciu. Dylemat ten można rozwiązać za pomocą krótkiego aliasu dla długiej nazwy przestrzeni nazw. Aliasy dla przestrzeni nazw tworzymy za pomocą słowa kluczowego namespace z dwiema nazwami namespace krótka = długa_nazwa_przestrzeni; Przykład: namespace American_Telephone_and_Telegraph { // tutaj zdefiniowano Napis } namespace ATT = American_Telephone_and_Telegraph; American_Telephone_and_Telegraph::Napis n = "x"; AAT::Napis nn = "y"; Nadużywanie aliasów może prowadzić do nieporozumień!

Komponowanie i wybór Interfejsy projektuje się po to, by zminimalizować zależności pomiędzy różnymi częściami programu. Minimalne interfejsy prowadzą do systemów łatwiejszych do zrozumienia, w których lepiej ukrywa się dane i implementację, łatwiej się je modyfikuje oraz szybciej kompiluje. Eleganckim narzędziem do konstruowania interfejsów są przestrzenie nazw.

Komponowanie i wybór Gdy chcemy utworzyć interfejs z istniejących już interfejsów to stosujemy komponowanie przestrzeni nazw za pomocą dyrektyw użycia, na przykład: namespace His_string { class String { /* ... */ }; String operator+ (const String&, const String&); String operator+ (const String&, const char*); void fill (char) ; // ... } namespace Her_vector { template<class T> class Vector { /* ... */ }; // ... } namespace My_lib { using namespace His_string; using namespace Her_vector; void my_fct(String&) ; } Dyrektywa użycia wprowadza do zasięgu wszystkie deklarację z podanej przestrzeni nazw.

Komponowanie i wybór Teraz przy pisaniu programu można posługiwać się My_lib: void f () { My_lib::String s = "Byron"; // znajduje My_lib::His_string::String // ... } using namespace My_lib; void g (Vector<String> &vs) { // ... my_fct(vs[5]); // ... }

Komponowanie i wybór Gdy chcemy utworzyć interfejs i dołożyć do niego kilka nazw z innych interfejsów to stosujemy wybór za pomocą deklaracji użycia, na przykład: namespace My_string { using His_string::String; using His_string::operator+; // … } Deklaracja użycia wprowadza do zasięgu każdą deklarację o podanej nazwie. Pojedyncza deklaracja użycia może wprowadzić każdy wariant funkcji przeciążonej.

Komponowanie i wybór Łączenie komponowania (za pomocą dyrektyw użycia) z wyborem (za pomocą deklaracji użycia) zapewnia elastyczność potrzebną w praktyce. Z użyciem tych mechanizmów możemy zapewnić dostęp do wielu udogodnień, a zarazem rozwiązać problem konfliktu nazw i niejednoznaczności wynikających z komponowania. Nazwy zadeklarowane jawnie w przestrzeni nazw (łącznie z nazwami wprowadzonymi za pomocą deklaracji użycia) mają pierwszeństwo przed nazwami wprowadzonymi za pomocą dyrektyw użycia. Nazwę w nowej przestrzeni nazw można zmienić za pomocą instrukcji typedef lub poprzez dziedziczenie.

Przestrzenie nazw są otwarte Przestrzeń nazw jest otwarta, co oznacza, że można do niej dodawać nowe pojęcia w kilku deklaracjach (być może rozmieszczonych w różnych plikach), na przykład: namespace NS { int f (); // NS ma nową składową f() } namespace NS { int g (); // teraz NS ma dwie składowe f() i g() } Definiując wcześniej zadeklarowaną składową w przestrzeni nazw, bezpieczniej jest użyć operatora zakresu niż ponownie otwierać przestrzeń (kompilator nie wykryje literówek w nazwie składowej), na przykład: namespace NS { int h (); } int NS::hhh () // błąd - zamiast h napisano hhh { /*…*/ }

Przestrzeń nazw std W języku C++ wszystkie nazwy z biblioteki standardowej są umieszczone w przestrzeni nazw std. W języku C tradycyjnie używa się plików nagłówkowych i wszystkie nazwy w nich deklarowane są w przestrzeni globalnej (dostępne bez żadnych kwalifikacji). Aby zapewnić możliwość kompilowania przez kompilatory C++ programów napisanych w C przyjęto, że jeśli użyjemy tradycyjnej (pochodzącej z C) nazwy pliku nagłówkowego, to odpowiedni plik jest włączany i zadeklarowane w nim nazwy są dodawane do globalnej przestrzeni nazw. Jeśli natomiast ten sam plik nagłówkowy włączymy pod nową nazwą, to nazwy w nim deklarowane są dodawane do przestrzeni nazw std. Przyjęto przy tym konwencję, że pliki nagłówkowe z C nazwie nazwa.h są w C++ nazywane cnazwa (pary plików <math.h> i <cmath>, itp).