1 / 29

C++ wykład 3 (7.03.2013)

C++ wykład 3 (7.03.2013). Składowe statyczne Funkcje wbudowane Argumenty domyślne Funkcje zaprzyjaźnione. Pola statyczne. Każdy obiekt danej klasy ma swój własny zestaw pól z danymi.

azize
Télécharger la présentation

C++ wykład 3 (7.03.2013)

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. C++wykład 3 (7.03.2013) Składowe statyczneFunkcje wbudowaneArgumenty domyślneFunkcje zaprzyjaźnione

  2. Pola statyczne • Każdy obiekt danej klasy ma swój własny zestaw pól z danymi. • Pole statyczne, z deklaratorem static, nie jest częścią obiektu, istnieje poza jakimkolwiek obiektem i jest wspólne dla wszystkich obiektów danej klasy. • Pole statyczne istnieje przez cały czas życia programu, nawet wtedy gdy nie utworzono żadnego obiektu danej klasy.

  3. Pola statyczne • Deklaracja pola statycznego w ciele klasy (w pliku nagłówkowym) nie jest jego definicją. • Przykład klasy z deklaracją pola statycznego:class data{ int dz, mies, rok;public: data (int d, int m, int r) : dz(d), mies(m), rok(r) {/*…*/}static data poczatek_kalendarza;}; • Definicję pola statycznego należy umieścić poza klasą (w pliku źródłowym). • Przykład definicji pola statycznego poza klasą:data data::poczatek_kalendarza(15,10,1582);

  4. Pola statyczne • Odniesienie się do pola statycznego poprzez nazwę klasy:klasa::pole_stat • Do pola statycznego można się też odnieść poprzez jakikolwiek obiekt danej klasy:klasa ob, *wsk;// …ob.pole_statwsk->pole_stat

  5. Statyczne funkcje składowe • Statyczna funkcja składowa, z deklaratorem static, nie odnosi się do żadnego obiektu danej klasy. • Statyczna funkcja składowa może być wywołana w dowolnym momencie, nawet wtedy gdy nie utworzono żadnego obiektu danej klasy. • Deklaracja statycznej funkcji składowej znajduje się w ciele klasy (w pliku nagłówkowym) a jej definicja jest poza klasą (w pliku źródłowym).

  6. Statyczne funkcje składowe • Przykład klasy z deklaracją statycznej funkcji składowej:class data{ int dz, mies, rok;public: data (int d, int m, int r) : dz(d), mies(m), rok(r) {/*…*/}static int roznica (data p, data k);}; • Przykład definicji statycznej funkcji składowej:int data::roznica (data p, data k) {/*…*/} • W ciele statycznej funkcji składowej nie wolno odnosić się do składowych instancyjnych ani do wskaźnika this. • Do statycznej funkcji składowej można odnieść się poprzez nazwę klasy albo poprzez jakikolwiek obiekt danej klasy.

  7. Funkcje wbudowane • Funkcje wbudowane, oznaczone deklaratorem inline, są rozwijane w miejscu wywołania. • Ich definicja musi być znana w momencie kompilacji a nie linkowania, dlatego nie tylko ich deklaracja ale również definicja znajduje się w pliku nagłówkowym. • Deklarator inline to tylko sugestia dla kompilatora aby wbudowywał funkcję w miejscu jej wywołania. • Funkcja inline zostanie skompilowane jako outline w przypadku, gdy: • kompilujemy program do pracy z debuggerem, • funkcja jest rekurencyjna, • pobieramy w programie adres funkcji.

  8. Funkcje wbudowane • Wbudowywanie funkcji w kod ma sens w przypadku krótkich funkcji. • Funkcje wbudowane zwiększają rozmiar programu wynikowego ale przyspieszają jego działanie. • Przykład funkcji wbudowanej:inline int zaokraglenie (double d){ return d<0? int(d-.5): int(d+.5);}

  9. Wbudowane funkcje składowe • W klasie też można definiować wbudowane funkcje składowe. • Metoda zdefiniowana w klasie jest traktowana jako inline. • Metody inline można także definiować poza klasą.

  10. Wbudowane funkcje składowe • Przykład klasy z metodami wbudowanymi:class data{ int dz, mies, r;public: data (int d, int m, int r); int dzien (void) const; int miesiac (void) const { return mies; } inline int rok (void) const { return r; }};inline data::data (int d, int m, int r): dz(d), mies(m), r(r) {}inline int data::dzien (void) const{ return dz; }

  11. Argumenty domyślne • Często mamy taką sytuację, że w ogólnym przypadku funkcja wymaga podania większej liczby argumentów niż w przypadku najprostszym, albo że wartości niektórych argumentów często się powtarzają. • Argumenty funkcji globalnych i funkcji składowych w klasie mogą posiadać argumenty domyślne. • Argumenty domyślne są formą przeciążania nazwy funkcji.

  12. Argumenty domyślne • Argumenty domyślne mogą występować tylko na końcu listy argumentów. • Wartości domyślne nadawane argumentom domyślnym podaje się tylko w deklaracji funkcji, w definicji się tego nie powtarza. • Przy wywoływaniu funkcji z argumentami domyślnymi można pomijać argumenty domyślne od końca. • Wszystkie argumenty mogą być domyślne.

  13. Argumenty domyślne • Przykład funkcji z argumentem domyślnym:// deklaracjavoid drukuj (int x, int podst=10);// definicjavoid drukuj (int x, int podst) {/*…*/}// wywołaniadrukuj(63); // wynik 63drukuj(63,16); // wynik 3Fdrukuj(63,2); // wynik 111111

  14. Nienazwane argumenty • Jeśli argumentu nazwanego nie używa się w ciele funkcji lub funkcji składowej, to kompilator będzie generował ostrzeżenia. • Argumenty, których nie używa się w ciele funkcji mogą nie posiadać swojej nazwy. • Również argumenty domyślne mogą nie posiadać nazwy. • Przykład funkcji z nienazwanym argumentem:void buczenie (int) { /*…*/ }

  15. Funkcja bez argumentów • Jeśli funkcja nie ma żadnych argumentów, to powinno się ją zadeklarować z argumentem void. • Przykład:void buczenie (void);// to jest równoważne z// void buczenie ();// w języku C byłoby to równoważne z // void buczenie (...);

  16. Funkcje zaprzyjaźnione • Problem z kwiatkami w domu w czasie dalekiej podróży służbowej. • Funkcja, która jest przyjacielem klasy, ma dostęp do wszystkich jej prywatnych i chronionych składowych. • To klasa deklaruje, które funkcje są jej przyjaciółmi. • Deklaracja przyjaźni może się pojawić w dowolnej sekcji i jest poprzedzona słowem kluczowym friend.

  17. Funkcje zaprzyjaźnione • Przykład klasy z funkcją zaprzyjaźnioną:// klasa z funkcją zaprzyjaźnionąclass pionek{ int x, y; // …friend void raport (const pionek &p);};// funkcja, która jest przyjacielem klasyvoid raport (const pionek &p){ cout << "(" << p.x << ", " << p.y << ")";}

  18. Funkcje zaprzyjaźnione • Nie ma znaczenia, w której sekcji (prywatnej, chronionej czy publicznej) pojawi się deklaracja przyjaźni. • Funkcja zaprzyjaźniona z klasą nie jest jej składową, nie może używać wskaźnika this w stosunku do obiektów tej klasy. • Jedna funkcja może się przyjaźnić z kilkoma klasami. • Istotą przyjaźni jest dostęp do niepublicznych składowych w klasie – sensowne jest deklarowanie przyjaźni, gdy dana funkcja pracuje z obiektami tej klasy.

  19. Funkcje zaprzyjaźnione • Można także umieścić w klasie nie tylko deklarację funkcji zaprzyjaźnionej, ale również jej definicję; tak zdefiniowana funkcja: • jest nadal tylko przyjacielem klasy; • jest inline; • może korzystać z typów zdefiniowanych w klasie. • Funkcją zaprzyjaźnioną może być funkcja składowa z innej klasy.

  20. Klasy zaprzyjaźnione • Możemy w klasie zadeklarować przyjaźń z inną klasą, co oznacza, że każda metoda tej innej klasy jest zaprzyjaźniona z klasą pierwotną. • Przykład:class A{friend class B; // …}; • Przyjaźń jest jednostronna. • Przyjaźń nie jest przechodnia. • Przyjaźni się nie dziedziczy.

  21. Klasy zaprzyjaźnione • Dwie klasy mogą się przyjaźnić z wzajemnością:class A;class B{friend class A; // …};class A{friend class B; // …};

  22. Nowości z C++11 – wskaźnik pusty nullptr • Wskaźnik pusty nullptr – zastępuje makro NULL albo 0. • Motywacja: w C NULL jest makrem preprocesora zdefiniowanym jako ((void*)0); w C++ niejawna konwersja z void* do wskaźnika innego typu jest niedozwolona, więc nawet takie proste przypisanie jak char* c = NULL mogłoby być w tym przypadku błędem kompilacji. • Sytuacja komplikuje się w przypadku przeciążania:void foo(char*);void foo(int);Gdy programista wywoła foo(NULL), to wywoła wersję foo(int), która prawie na pewno nie była przez niego zamierzona. • nullptr nie może być przypisane do typów całkowitych, ani porównywane z nimi; może być porównywane z dowolnymi typami wskaźnikowymi.

  23. Nowości z C++11 – pętla for oparta na zakresie • Zakresy reprezentują kontrolowaną listę pomiędzy dwoma jej punktami. Kontenery uporządkowane są nad zbiorem koncepcji zakresu i dwa iteratory w kontenerze uporządkowanym także definiują zakres. • Nowa pętla for została stworzona do łatwej iteracji po zakresie; jej ogólna postać jest następująca:for (TYP &x: kolekcja<TYP>) instrukcja; • Przykład:int moja_tablica[5] = {1, 2, 3, 4, 5};for(int &x: moja_tablica) { x *= 2; } • Pierwsza sekcja nowego for (przed dwukropkiem) definiuje zmienną, która będzie użyta do iterowania po zakresie. Zmienna ta, tak jak zmienne w zwykłej pętli for, ma zasięg ograniczony do zasięgu pętli. • Druga sekcja (po dwukropku), reprezentuje iterowany zakres. W tym przypadku, zwykła tablica jest konwertowana do zakresu. Mógłby to być na przykład std::vector albo inny obiekt spełniający koncepcję zakresu.

  24. Nowości z C++11 – uogólnione wyrażenia stałe • Stałe wyrażenia zawsze zwracają ten sam wynik i nie wywołują żadnych dodatkowych efektów ubocznych – są one dla kompilatorów okazją do optymalizacji, ponieważ kompilatory często wykonują te wyrażenia w czasie kompilacji i wstawiają ich wyniki do programu. • Słowo kluczowe constexpr pozwala programiście zagwarantować, że funkcja lub konstruktor obiektu są stałymi podczas kompilacji.

  25. Nowości z C++11 – uogólnione wyrażenia stałe • Zastosowanie constexpr do funkcji narzuca bardzo ścisłe ograniczenia na to, co funkcja może robić: • funkcja musi posiadać typ zwracany różny od void; • zawartość funkcji musi być postaci return wyrażenie; • wyrażenie musi być stałym wyrażeniem po zastąpieniu argumentu (to stałe wyrażenie może albo wywołać inne funkcje tylko wtedy, gdy te funkcje też są zadeklarowane ze słowem kluczowym constexpr albo używać inne stałe wyrażenia); • wszystkie formy rekurencji w stałych wyrażeniach są zabronione; • funkcja zadeklarowana ze słowem kluczowym constexpr nie może być wywoływana, dopóki nie będzie zdefiniowana w swojej jednostce translacyjnej. • Przykład:constexpr int GetFive() {return 5;}int someValues[GetFive() + 5];

  26. Nowości z C++11 – uogólnione wyrażenia stałe • Zmienne stałowyrażeniowe typu constexpr są niejawnie typu const – mogą one przechować wyniki wyrażeń stałych lub stałowyrażeniowych konstruktorów (czyli zdefiniowanych ze słowem kluczowym constexpr). • Przykład:constexpr double grawitacja = 9.8;constexpr double grawitacjaKsiezyca = grawitacja / 6; • Stałowyrażeniowy konstruktor służy do konstrukcji wartości stałowyrażeniowych z typów zdefiniowanych przez użytkownika, konstruktory takie muszą być zadeklarowane jako constexpr. • Stałowyrażeniowy konstruktor musi być zdefiniowany przed użyciem w jednostce translacyjnej (podobnie jak metoda stałowyrażeniowa) i musi mieć puste ciało funkcji i musi inicjalizować swoje składowe za pomocą stałych wyrażeń. • Destruktory takich typów powinny być trywialne.

  27. Nowości z C++11 – referencja do r-wartości • Obiekty tymczasowe (określane jako r-wartości), to wartości stojące po prawej stronie operatora przypisania (analogicznie zwykła referencja do zmiennej stojącej po lewej stronie przypisania nazywa się l-wartością). • Argument w funkcji będący referencją do r-wartości definiujemy jako TYP &&arg. • Argument będący r-referencją może być akceptowany jako niestała wartość, co pozwala funkcjom na ich modyfikację. • Argumenty r-referencyjne umożliwiają pewnym obiektom na stworzenie semantyki przenoszenia za pomocą konstruktorów przenoszących definiowanych jako TYP::TYP (TYP &&arg) oraz przypisań przenoszących.

  28. Nowości z C++11 – referencja do r-wartości • Przykład:class Simple { void *Memory; // The resourcepublic: Simple() { Memory = nullptr; } // the MOVE-CONSTRUCTOR Simple(Simple&& sObj) { // Take ownership Memory = sObj.Memory; // Detach ownership sObj.Memory = nullptr; } Simple(int nBytes) { Memory = new char[nBytes]; } ~Simple() { if(Memory != nullptr) delete[] Memory; }};

  29. Nowości z C++11 – referencja do r-wartości • Przykład:Simple GetSimple() { Simple sObj(10); return sObj; } // R-Value NON-CONST referencevoid SetSimple(Simple&& rSimple) { // performing memory assignment here Simple object; object.Memory = rSimple.Memory; rSimple.Memory = nullptr; // Use object... delete[] object.Memory; }

More Related