Automatyczne tworzenie operatora = Integer2& operator=(const Integer& prawy) {

Podobne dokumenty
Automatyczne tworzenie operatora = Integer2& operator=(const Integer& prawy) { zdefiniuje. Integer::operator=(ri);

Automatyczne tworzenie operatora = Integer2& operator=(const Integer& prawy) {

C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów

C++ - szablony. C++ - szablony. C++ - szablony. C++ - szablony. C++ - szablony. C++ - szablony

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy WSKAŹNIKI KLASOWE

Szablony. Szablony funkcji

Szablony klas, zastosowanie szablonów w programach

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

Szablony funkcji i klas (templates)

C++ - szablony. C++ - szablony. C++ - szablony. C++ - szablony SZABLONY SZABLONY FUNKCJI

PARADYGMATY PROGRAMOWANIA Wykład 4

Klasa jest nowym typem danych zdefiniowanym przez użytkownika. Najprostsza klasa jest po prostu strukturą, np

Szablony funkcji i szablony klas

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy INNE SPOSOBY INICJALIZACJI SKŁADOWYCH OBIEKTU

IMIĘ i NAZWISKO: Pytania i (przykładowe) Odpowiedzi

Programowanie, część I

1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość

1. Które składowe klasa posiada zawsze, niezależnie od tego czy je zdefiniujemy, czy nie?

W2 Wprowadzenie do klas C++ Klasa najważniejsze pojęcie C++. To jest mechanizm do tworzenia obiektów. Deklaracje klasy :

TEMAT : KLASY DZIEDZICZENIE

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

C++ Przeładowanie operatorów i wzorce w klasach

Zaawansowane programowanie w języku C++ Funkcje uogólnione - wzorce

Funkcje wirtualne. Wskaźniki do klas pochodnych są podstawą dla funkcji wirtualnych i polimorfizmu dynamicznego.

Obsługa wyjątków. Język C++ WW12

C++ - dziedziczenie. C++ - dziedziczenie. C++ - dziedziczenie. C++ - dziedziczenie. C++ - dziedziczenie C++ - DZIEDZICZENIE.

Programowanie w C++ Wykład 12. Katarzyna Grzelak. 28 maja K.Grzelak (Wykład 12) Programowanie w C++ 1 / 27

Abstrakcyjny typ danych

C++ - polimorfizm. C++ - polimorfizm. C++ - polimorfizm. C++ - polimorfizm. C++ - polimorfizm POLIMORFIZM

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy INNE SPOSOBY INICJALIZACJI SKŁADOWYCH OBIEKTU

Programowanie w języku C++

Programowanie w C++ Wykład 11. Katarzyna Grzelak. 13 maja K.Grzelak (Wykład 11) Programowanie w C++ 1 / 30

Dariusz Brzeziński. Politechnika Poznańska, Instytut Informatyki

Wykład 8: klasy cz. 4

Zaawansowane programowanie w C++ (PCP)

Składnia C++ Programowanie Obiektowe Mateusz Cicheński

Wstęp do programowania

Wprowadzenie w dziedziczenie. Klasa D dziedziczy klasę B: Klasa B klasa bazowa (base class), klasa D klasa pochodna (derived class).

EGZAMIN 2 (14 WRZEŚNIA 2015) JĘZYK C++

Wprowadzenie do szablonów szablony funkcji

Zaawansowane programowanie w języku C++ Programowanie obiektowe

Programowanie obiektowe Wykład 6. Dariusz Wardowski. dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/14

ISO/ANSI C - funkcje. Funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje

Wprowadzenie do szablonów szablony funkcji

Wskaźniki. Informatyka

PARADYGMATY PROGRAMOWANIA Wykład 3

Strona główna. Strona tytułowa. Programowanie. Spis treści. Sobera Jolanta Strona 1 z 26. Powrót. Full Screen. Zamknij.

EGZAMIN PROGRAMOWANIE II (10 czerwca 2010) pytania i odpowiedzi

Programowanie obiektowe w C++ Wykład 12

Przeciążenie operatorów

Programowanie obiektowe Wykład 3. Dariusz Wardowski. dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/21

Tablice (jedno i wielowymiarowe), łańcuchy znaków

Obszar statyczny dane dostępne w dowolnym momencie podczas pracy programu (wprowadzone słowem kluczowym static),

Część 4 życie programu

Podział programu na moduły

Programowanie, część I

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy KONSTRUKTORY

Programowanie komputerowe. Zajęcia 7

Projektowanie klas c.d. Projektowanie klas przykład

Kurs programowania. Wykład 1. Wojciech Macyna. 3 marca 2016

Programowanie w C++ Wykład 8. Katarzyna Grzelak. 15 kwietnia K.Grzelak (Wykład 8) Programowanie w C++ 1 / 33

Konstruktory. Streszczenie Celem wykładu jest zaprezentowanie konstruktorów w Javie, syntaktyki oraz zalet ich stosowania. Czas wykładu 45 minut.

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy PRAWA PRZYJACIÓŁ KLASY. Dostęp z zewnątrz: Dostęp z wewnątrz:

FUNKCJE WZORCOWE. Wykład 10. Programowanie Obiektowe (język C++) Funkcje wzorcowe wprowadzenie (2) Funkcje wzorcowe wprowadzenie (1)

Obiekt klasy jest definiowany poprzez jej składniki. Składnikami są różne zmienne oraz funkcje. Składniki opisują rzeczywisty stan obiektu.

Operator przypisania. Jest czym innym niż konstruktor kopiujący!

Język C++ umożliwia przeciążanie operatora, tzn. zmianę jego znaczenia na potrzeby danej klasy. W tym celu definiujemy funkcję o nazwie:

Język C++ zajęcia nr 2

Programowanie w C++ Wykład 13. Katarzyna Grzelak. 4 czerwca K.Grzelak (Wykład 13) Programowanie w C++ 1 / 26

Java - tablice, konstruktory, dziedziczenie i hermetyzacja

Wykład 5: Klasy cz. 3

Techniki programowania INP001002Wl rok akademicki 2018/19 semestr letni. Wykład 3. Karol Tarnowski A-1 p.

Składnia C++ Programowanie Obiektowe Mateusz Cicheński

Kurs programowania. Wykład 3. Wojciech Macyna. 22 marca 2019

Katedra Elektrotechniki Teoretycznej i Informatyki. wykład 12 - sem.iii. M. Czyżak

Funkcje. Spotkanie 5. Tworzenie i używanie funkcji. Przekazywanie argumentów do funkcji. Domyślne wartości argumentów

Paradygmaty programowania. Paradygmaty programowania

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

wykład II uzupełnienie notatek: dr Jerzy Białkowski Programowanie C/C++ Język C - funkcje, tablice i wskaźniki wykład II dr Jarosław Mederski Spis

Programowanie w C++ Wykład 9. Katarzyna Grzelak. 14 maja K.Grzelak (Wykład 9) Programowanie w C++ 1 / 30

Programowanie współbieżne Wykład 8 Podstawy programowania obiektowego. Iwona Kochaoska

Laboratorium nr 10. Temat: Funkcje cz.2.

Jeśli chcesz łatwo i szybko opanować podstawy C++, sięgnij po tę książkę.

Laboratorium nr 12. Temat: Struktury, klasy. Zakres laboratorium:

Functionalization. Funkcje w C. Marcin Makowski. 30 listopada Zak lad Chemii Teoretycznej UJ

Programowanie obiektowe, wykład nr 7. Przegląd typów strukturalnych - klasy i obiekty - c.d.

Podstawy programowania skrót z wykładów:

Wstęp do Programowania, laboratorium 02

Programowanie w C++ Wykład 5. Katarzyna Grzelak. 26 marca kwietnia K.Grzelak (Wykład 1) Programowanie w C++ 1 / 40

Funkcje przeciążone, konstruktory kopiujące, argumenty domyślne

Identyfikacje typu na etapie. wykonania (RTTI)

Programowanie obiektowe i C++ dla matematyków

Programowanie obiektowe. Materiały przygotował: mgr inż. Wojciech Frohmberg

Wykład 5 Okna MDI i SDI, dziedziczenie

Wykład V. Programowanie II - semestr II Kierunek Informatyka. dr inż. Janusz Słupik. Wydział Matematyki Stosowanej Politechniki Śląskiej

Wskaźniki a tablice Wskaźniki i tablice są ze sobą w języku C++ ściśle związane. Aby się o tym przekonać wykonajmy cwiczenie.

Instrukcja do pracowni specjalistycznej z przedmiotu. Obiektowe programowanie aplikacji

Programowanie w C++ Wykład 14. Katarzyna Grzelak. 3 czerwca K.Grzelak (Wykład 14) Programowanie w C++ 1 / 27

1 Podstawy c++ w pigułce.

Transkrypt:

Przeciążanie operatorów [] Przykład: klasa reprezentująca typ tablicowy. Obiekt ma reprezentować tablicę, do której można się odwoływać intuicyjnie, np. Tab[i] Ma być też dostępnych kilka innych metod ułatwiających operacje na tej tablicy, np. rozmiar(). Przykład: class Tablica int rozm; int *wsk; Tablica( int = 10 ); Tablica( const Tablica& ); ~Tablica(); int rozmiar(void) const return rozm; const Tablica &operator=( const Tablica& ); bool operator==( const Tablica& ); int &operator[]( int ); const int &operator[]( int ) const; 239 240 ; Implementacja przeciążonego operatora []: int &Tablica::operator[]( int i) assert (0 <= i && i < rozm); return wsk[i]; // operator dla obiektów zadeklarowanych jako const const int &Tablica::operator[]( int i) const assert (0 <= i && i < rozm); return wsk[i]; Przykład wykorzystania: Tablica Tab1(5), Tab2; for (int i=0; i<tab1.rozmiar(); i++) Tab1[i] = i; Tab2 = Tab1; assert(tab2 == Tab1); 241 242 Przeciążanie a dziedziczenie class Integer2: public Integer Operatory, z wyjątkiem operatora przypisania są automatycznie dziedziczone w klasach pochodnych. Integer2(int i): Integer(i) Automatyczne tworzenie operatora = Integer2& operator=(const Integer& prawy) Ponieważ programiści oczekują, że operacja przypisania dla dwóch zmiennych class Integer Integer::operator=(prawy); jednakowego typu zawsze powinna się powieść, dlatego kompilator zawsze automatycznie tworzy ten operator, jeżeli programista go nie Integer(int ii): i(ii) Integer2& operator=(int ri) zdefiniuje. Integer& operator+=(const Integer& rv) Integer::operator=(ri); Działanie tego operatora jest identyczne jak domyślnego konstruktora i += rv.i; kopiującego: jeżeli klasa zawiera składowe obiekty, to dla każdego z nich wywoływany Integer& operator=(const Integer &rv) jest rekurencyjnie operator = (tzw. przypisanie za pośrednictwem i = rv.i; elementów składowych). Integer2 I2(1), J2(0); Integer K1(9); Nie należy na to pozwalać kompilatorowi, ale samemu pisać operator Integer& operator=(int ri) J2 = 5; // metoda własna przypisania, jeżeli planuje się go używać zdanie się na automatycznie i = ri; I2 = K1; // metoda własna wygenerowane operatory łatwo prowadzi do błędów. J2 = I2; //? I2 += J2; // metoda dziedziczona 243 244 1

Automatyczna konwersja typów 1. może być realizowana za pomocą konstruktora, pobierającego jako jedyny argument obiekt lub referencje do obiektu innego typu, lub 2. może być realizowana przez napisanie specjalnych przeciążonych operatorów class Jeden Jeden() class Dwa Dwa(const Jeden&) // sposób 1: // specjalny konstruktor void f(dwa) Jeden J; f(j); // kompilator to akceptuje, bo w Dwa zadeklarowano // konstruktor, którego argumentem jest obiekt typu Jeden 245 246 Może się zdarzyć, że nie chcemy, aby konstruktor był wywoływany automatycznie, jeżeli zajdą takie okoliczności, w których mógłby być tak wywołany Aby zablokować automat, używamy słowa explicit class Jeden Jeden() class Dwa explicit Dwa(const Jeden&) void f(dwa) Jeden J; // f(j)- ta instrukcja nie zadziała, bo zablokowano automatyczną konwersję f(dwa(j)); 247 248 Sposób 2: Automatyczna konwersja typów za pomocą operatora konwersji Można utworzyć funkcję składową, pobierającą aktualny typ i przekształcającą go na typ docelowy, wykorzystując słowo kluczowe operator W takiej składowej słowo operator poprzedza nazwę typu do którego ma zostać dokonana konwersja, zamiast symbolu operatora class Trzy Trzy(int ii): i(ii) class Cztery int x; Cztery(int xx): x(xx) operator Trzy() const return Trzy(x); void g(trzy) int main(int argc, char *argv[]) Cztery cz(1); g(cz); // wywołanie operatora g(1); // wywołanie Trzy(1.0) 249 250 2

Automatyczna konwersja typów podsumowanie: Przewaga globalnych przeciążonych operatorów nad operatorami będącymi składowymi klas podsumowanie: 1. może być realizowana za pomocą konstruktora, pobierającego jako jedyny argument obiekt lub referencje do obiektu innego typu. Utworzenie jednoargumentowego konstruktora zawsze definiuje automatyczną konwersję typów nawet jeżeli argumentów jest więcej, ale pozostałe posiadają wartości domyślne. Jeżeli chcemy tego uniknąć, deklarujemy ten w przypadku operatorów globalnych konwersja typów może zostać konstruktor jako explicit. zastosowana do każdego z argumentów To klasa docelowa musi mieć odpowiedni konstruktor: w przypadku składowej argument po lewej stronie operatora musi być Dwa::Dwa(const Jeden&) odpowiedniego typu void f(dwa) 2. może być realizowana przez napisanie specjalnych przeciążonych operatorów To klasa źródłowa musi mieć odpowiedni operator konwersji: Cztery::operator Trzy() const return Trzy(x); void g(trzy) 251 252 class Integer Integer(int ii): i(ii) const Integer operator+(const Integer& rv) return Integer(i+rv.i); friend const Integer operator/(const Integer &arg_lewy, const Integer &arg_prawy); const Integer operator/(const Integer &arg_lewy, const Integer &arg_prawy) if (arg_prawy.i == 0) return Integer(INT_MAX); else return Integer(arg_lewy.i/arg_prawy.i); Integer I(1), J(2), K(3); I = J + 5; //I = 5 + J; // to się nie uda I = K/2; I = 10/K; // tak jest OK Czego należy unikać podsumowanie: Deklarowania dwóch sposobów konwersji jednocześnie. Jeżeli: klasa X posiada możliwość przekształcenia obiektu w obiekt klasy Y za pomocą operatora Y(), a jednocześnie: klasa Y posiada konstruktor, pobierający pojedynczy argument typu X to: obydwa mechanizmy reprezentują tę samą konwersje typów i w razie potrzeby kompilator nie wie, której użyć wtedy zgłasza błąd dwuznaczności. 253 254 SZABLONY 255 3

Szablony, nazywane też wzorcami, pozwalają na abstrakcyjne definiowanie funkcji i klas w terminach parametrów, którymi są typy danych Na podstawie szablonu kompilator sam może wygenerować wiele definicji konkretnych funkcji i klas, kiedy będą potrzebne Standardowa biblioteka C++ bazuje na szablonach i dlatego jest nazywana STL: Standard Template Library część 1: SZABLONY FUNKCJI 257 Szablony funkcji Zdarza się, że wiele funkcji jest do siebie bardzo podobnych w działaniu różnią się tylko typem argumentu, który przyjmują Np. funkcja która z tablicy wybiera element o najmniejszej wartości: algorytm szukania jest wspólny dla większości typów danych. Jednak jeżeli chcemy znajdować najmniejszą wartość dla tablic z elementami typu: int, double, lub Integer (zdefiniowana klasa, dla której istnieje przeciążony operator porównania), to dla każdego z typów należy napisać na nowo całą funkcję Jeżeli te funkcje będą fragmentem biblioteki, to za każdym razem kiedy będziemy potrzebowali dopisać funkcję dla nowego typu danych w tablicy, będzie trzeba rekompilować bibliotekę i udostępniać jej użytkownikom nowy release Kompilator tworzy tyle wersji funkcji wg wskazanego szablonu, ile programista zażąda w swoim programie: będą takie same co do działania, ale będą różniły się co do typów argumentów wywołania, typów zmiennych lokalnych czy typu wartości zwracanej Można je generować nawet dla typów, które w chwili pisania szablonu jeszcze w ogóle nie istniały Aby poinformować kompilator, że kod, który piszemy reprezentuje szablon, należy użyć słowa kluczowego template - kod, który znajduje się poniżej tego słowa jest definicją wzorca funkcji lub klasy To jest uciążliwe. Lepiej zrobić tę funkcję raz wykorzystując szablony. 259 260 Przykład: template <class T1, class T2> T2& moja_funkcja(t1 arg1, T2* arg2) // Tutaj jakiś kod funkcji // wykorzystującej typy T1 i T2 return *arg2; W nawiasach kątowych lista parametrów formalnych wzorca, każdy poprzedzony słowem class, lub typename (typename wprowadzono później) Parametry zwyczajowo nazywa się z wykorzystaniem T, np. T1, T2 Następnie występuje definicja wzorca wykorzystująca T1 i T2 tam, gdzie powinna występować nazwa konkretnego typu Na podstawie typów argumentów kompilator ma zgadnąć, który szablon i jak należy wykorzystać: template <class T1, class T2> T2& moja_funkcja(t1 arg1, T2* arg2) return *arg2; int a = 9; double b = 10.2, c = 3.14; moja_funkcja(a, &b); // konkretyzacja wzorca na // double& moja_funkcja(int arg1, double* arg2) moja_funkcja(a, &c); // tu nie ma konkretyzacji funkcja już jest. moja_funkcja(b, &a); // konkretyzacja wzorca na //int& moja_funkcja(double arg1, int* arg2) 261 262 4

Słowo kluczowe class w linii: template <class T1, class T2> nie oznacza, że T1 i T2 mogą być tylko klasami (jak widać na przykładzie); mogą to być dowolne typy (wbudowane lub definiowane przez użytkownika) Dla czytelności w późniejszych wersjach kompilatorów zastąpiono to słowo słowem typename template < typename T1, typename T2> Przeciążanie szablonów funkcji: template <typename T> T wiekszy(const T& k1, const T& k2) return k1 < k2? k2 : k1 ; double wiekszy(const double& d1, const double& d2) return d1 < d2? d2 : d1 ; int a, b=0, c=1; a = wiekszy(b,c); // która wersja funkcji zostanie użyta? // Istnieje standardowa konwersja int na double, ale // istnieje też szablon wg którego można utworzyć // właściwą funkcję double x, y=0.3, z=2.14; x = wiekszy(y,z); // która wersja funkcji zostanie użyta? 263 264 Wskazywanie wartości parametru szablonu class Integer Integer(int ii): i(ii) bool operator<( const Integer& rv) const return i < rv.i; bool operator>( const Integer& rv) const return i > rv.i; template <typename T> T wiekszy(const T& k1, const T& k2) return k1 < k2? k2 : k1 ; Integer I1(0), I2(1), I3(2); I1 = wiekszy<integer>(i2, I3); Jeżeli nie ma jednoznacznej interpretacji, można za nazwą szablonu w nawiasach kątowych podać listę typów, które należy w tym miejscu zastosować Informacja o typie zmiennej Testując szablony czasem niezbędne jest sprawdzenie, jakiego typu są zmienne, których szablon używa (czy np. kompilator sam podjął decyzję o konwersji zmiennej na podobny typ, etc) Do sprawdzenia służy operator typeid Operator zwraca obiekt typu const std::type_info Klasa ta ma pożyteczną metodę name() 265 266 Chciałoby się napisać: std::type_info typ = typeid(a); printf("%s\n",typ.name()); Jednak autorzy biblioteki sprytnie zastrzegli konstruktor kopiujący oraz operator przypisania jako private uniemożliwiając de facto tworzenie w programie własnych obiektów tego typu z obiektów zwracanych przez operator typeid: private: /// Assigning type_info is not supported. Made private. type_info& operator=(const type_info&); type_info(const type_info&); Dlatego aby wywołać metodę name można wyłącznie napisać tak: printf("%s\n",typeid(k1).name()); Porada programistyczna Na etapie testowania programu można w szablonie funkcji i w funkcji dodać instrukcje ujawniające typ danych, które są przetwarzane: template <typename T> T wiekszy(const T& k1, const T& k2) printf("szablon dla: %s\n",typeid(k1).name()); return k1 < k2? k2 : k1 ; double wiekszy(const double& d1, const double& d2) printf("dla double: %s\n",typeid(d1).name()); return d1 < d2? d2 : d1 ; 267 268 5

część 2: SZABLONY KLAS Szablony klas Na tej samej zasadzie co szablony funkcji można tworzyć szablony klas Składnia jest analogiczna: template <typename T, typename M> class Klasa // tu używamy typów T i M Aby utworzyć obiekt nie możemy napisać: Klasa K; bo nie wiadomo, jakie typy przypisać parametrom M i T, a kompilator nie ma szansy domyślić się. Wskazanie wartości parametrów jest konieczne. 270 Szablony klas Deklaracja obiektów: template <typename T, typename M> class Klasa // tu używamy typów T i M Klasa<double, int> K; Klasa<int, Integer> I; Szablony klas Jeżeli chcemy, żeby metody tej klasy zostały definiowane poza szablonem klasy, to musimy tam prawidłowo napisać nazwę szablonu: Klasa::Klasa(); // konstruktor domyślny Źle! template <typename T, typename M> Klasa<T, M>::Klasa(); // kontruktor domyślny Dobrze! 271 272 Parametry szablonu klasy mogą być też wartościami określonego typu, np. : template <typename T, int rozmiar > class Klasa // tu używamy typu T i zmiennej rozmiar Klasa<int, 100> Tab; Klasa<double, 2000> *Tab2; Klasa<double, 3000> *Tab3; Projekt składający się z pliku main.cpp i biblioteki (para plików:.cpp i.h) wyklad13b.h template <typename T, int rozmiar> class Tablica wyklad13b.cpp #include wyklad13b.h" Tab, Tab2 i Tab3 są obiektami różnych typów, dlatego kompilator nie zaakceptuje takich instrukcji jak przepisanie wartości między wskaźnikami, itp. 273 main.cpp #include wyklad13b.h" Tablica<int, 100> Tab1; 274 6

Kompilacja szablonów Zawsze kiedy ukonkretniany jest szablon klasy, kod definicji takiej klasy dla danej specjalizacji jest generowany wraz z metodami składowymi wywoływanymi w programie i tylko z tymi rzeczywiście wywoływanymi metodami składowymi. Jest to unikanie nadmiarowego kodu. To daje możliwość elastycznego projektowania szablonów, wykorzystującego różne właściwości różnych konkretnych typów. class Pierwsza void f() class Druga void g() template<typename T> class Trzecia T t; void a() t.f(); void b() t.g(); int main() Trzecia<Pierwsza> TP; TP.a(); // nie tworzy Trzecia<Pierwsza>::b() 275 Trzecia<Druga> TD; TD.b(); // nie tworzy Trzecia<Druga>::a() 276 Szablony vs. pliki nagłówkowe Zasada: deklaracje i kompletne definicje szablonów funkcji i klas umieszczamy w pliku nagłówkowym (i tylko tam). Uzasadnienie: Skoro szablony są wykorzystywane do generowania kodu tylko gdy w kodzie wystąpi wykorzystanie szablonu, to: 1. Umieszczenie kodu metod i funkcji w pliku cpp sprawi, że będzie on kompilowany oddzielnie nie będzie w tym pliku instrukcji wykorzystujących szablon, które należą do innych funkcji i metod, a więc kompilator nie będzie wiedział jakich konkretyzacji dokonać 2. Tam, gdzie będą próby wykorzystania szablonu, kompilator będzie miał same nagłówki klas i funkcji, ale bez definicji, więc nie będzie potrafił skonkretyzować żądanych wersji szablonu Efekt uboczny: kod szablonów jest jawny dla każdego użytkownika naszej biblioteki (pliki nagłówkowe są dostarczane zawsze w postaci źródłowej) 277 7