• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

C++ Analiza kodu #2

VPS Starter Arubacloud
0 głosów
425 wizyt
pytanie zadane 27 sierpnia 2016 w C i C++ przez Itan Początkujący (250 p.)

Witam ponownie,

ostatnio prosiłem Was o analizę tego kodu: http://forum.pasja-informatyki.pl/169353/c-analiza-kodu dzięki czemu wiele mi się wyjaśniło, więc jeszcze raz bardzo dziękuję użytkownikowi Criss.

Jednak mam wiele zadań do omówienia z programowania obiektowego i ostatnio męczę się z szablonami klas. Poczytałem o tym, jednak brakuje mi tak jak poprzednio - analizy.

 

#include <iostream>
#include <vector>
#include <typeinfo>

using namespace std;

class O
{
protected:
    int v;
public:
    O(int v): v(v) {}
    void operator() (int &e)
    {
        e=e-v;
    }
};

template<class I, class F> void p(I b, I e, F f)
{
    I i=b;
    do
    {
        f(*i);
        cout << *i << " ";
        i = i+1;
    }
    while(i != e);
}

void f(int &e)
{
    e+=2;
}

int main()
{
    // 1.
    int t[5] = {-2, 4, 3, 2, 1};
    p(t, t+4, f);

    // 2.
    vector<int> v;
    v.push_back(1);
    v.push_back(-4);
    O o(-1);
    p(v.begin(), v.end(), o);

    return 0;
}

Zakładamy pewne definicje i w miejscach 1. oraz 2. mamy polecenie "Przy poniższych instrukcjach podaj co zostanie wypisane na ekranie". Wyniki poznałem, ale gubię się w jakiej kolejności te zmienne przechodzą przez ten kod.

Pozdrawiam

1 odpowiedź

+3 głosów
odpowiedź 27 sierpnia 2016 przez criss Mędrzec (172,590 p.)
wybrane 27 sierpnia 2016 przez Itan
 
Najlepsza

 To znowu ja :D

Na początku powiedzmy sobie, że nazwa funkcji jest wskaźnikiem na nią. Możemy w taki sposób przekazać funkcje do innej funkcji tak jak widać na przykładzie pierwszej instancji template-a funkcji p.

Druga sprawa - klasa O ma zdefiniowany operator(), więc możemy jej obiektów używać jak funkcji (tzn. z poziomu kodu tak to wygląda). Takie klasy nazywane są funktorami btw.

Tak więc w pierwszym przypadku:

Do p przekazujemy wskaźnik na int wskazujący na 0 element tablicy i jako drugi parametr wskaźnik wskazujący (4 * sizeof(int)) komórek* dalej (na czwarty, ostatni element). Przekazujemy też funkcje f o czym wcześniej mówiłem. Wewnątrz funkcji p mamy prostą pętle. Został wykorzystany do...while tak więc pętla się zatrzyma zaraz po obejściu w którym i == e. Pętla każdy obiekt (tutaj int), między zakresem ustalonym wskaźnikami (w 1 i 2 parametrze funkcji), przekazuje do funkcji f. A że funkcja f przyjmuje referencje, to działa na oryginalnej zmiennej i do każdego inta dodaje 2. Także za 40. linią każdy element tablicy t ma wartość o 2 większą.

W drugim przypadku dokładnie to samo, tylko zamiast funkcji f korzystamy z O::operator() wywoływanego z obiektu (a właściwie jego kopii, bo funkcja p (ta instancja, bo to szablon ofc) nie przyjmuje przez referencje i skopiuje sobie obiekt, ale nie obchodzi nas to specjalnie w tym przypadku). Skoro przy tworzeniu o podaliśmy do konstruktora -1, to O::operator() od każdego elementu tablicy odejmie -1 (czyli doda 1) - bo też przyjmuje przez referencje.

Jeszcze jedno - tutaj nie korzystaliśmy ze zwykłych wskaźników, a z iteratorów, ale one też mają zdefiniowany operator++ i !=, więc nie ma problemu. Działają na tej samej zasadzie. Iteratory możesz traktować jak wskaźniki ale wewnątrz-kontenerowe (wskazują na elementy konkretnej klasy kontenera).

Nie musieliśmy sami definiować parametrów szablonu, bo zostały automatycznie ustalone przez kompilator na podstawie przekazywanych typów.

* - miałem na myśli komórki pamięci, nie tablicy. Dla tablicy to oczywiście są 4 komórki.

Btw.: w kodzie jest "mały" błąd. W przypadku intów crash nie jest pewny, ale gdyby to był vector jakichś obiektów i funkcja p próbowałaby dostać się do jakichś składowych obiektu, to crash gwarantowany. Konkretnie w drugim przypadku w ostatniej iteracji O::operator() dodaje do *(v.end()), a .end() zwraca iterator na "element za ostatnim elementem" (nieistniejący)...

komentarz 27 sierpnia 2016 przez Itan Początkujący (250 p.)
Mocarz. Jesteś super! Na początku widziałem tylko chaos w tym kodzie, nawet pomimo przeczytania i przeanalizowania wielu przykładów z szablonami. A tu? Wystarczy, że napiszesz raz i wszystko jasne, dokładne i treściwe wyjaśnienie.

Bardzo Ci dziękuję i pozdrawiam :)
komentarz 28 sierpnia 2016 przez criss Mędrzec (172,590 p.)
Super, ciesze się, że tutaj też jasno wyjaśniłem, bo nie byłem pewien czy to jest tak samo "wyjaśnialne" jak poprzedni kod. :D

Podobne pytania

0 głosów
1 odpowiedź 680 wizyt
pytanie zadane 27 sierpnia 2016 w C i C++ przez Itan Początkujący (250 p.)
0 głosów
1 odpowiedź 532 wizyt
pytanie zadane 16 sierpnia 2016 w C i C++ przez Itan Początkujący (250 p.)
0 głosów
0 odpowiedzi 222 wizyt
pytanie zadane 26 marca 2017 w JavaScript przez marcinconn Obywatel (1,560 p.)

92,453 zapytań

141,262 odpowiedzi

319,086 komentarzy

61,854 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...