Static

tharos

Zmienne lokalne

Modyfikator static sprawia, że obiekt w danej [[C/funkcje|funkcji]] jest umieszczany w tej samej pamięci, co [[C/zmienne|zmienna]] globalna i nie jest usuwany wraz z zakończeniem funkcji.
//....
int licznik()
{
  static int a;
  a++;
  return a;
}

//...
int main()
{
  printf("Wywoluje funkcje licznik %d", licznik());
  printf("\n...drugi raz %d", licznik());
  //...
}

Zmienna lokalne statyczna nie jest usuwana. Będzie cały czas pamiętała swoją poprzednią wartość.
Zmienne lokalne statyczne są automatycznie inicjalizowane wartością 0.

Pola klasy

Statyczne pola klasy definiuje sie podobnie do zmiennych lokalnych, poprzez użycie słowa kluczowego static: ```cpp //.... class olowek { private: // dane opisujace olowek public: static int cena; }; ```

Podobnie jak zmienna statyczna lokalna, statyczne pole klasy jest tworzone tylko raz, w tym samym obszarze co zmienne globalne i cały czas pamięta swoją ostatnią wartość. Pole statyczne jest tworzone zanim zostanie utworzony pierwszy obiekt danej Klasy, jednak nie można określić kiedy to się stanie dokładnie. Zazwyczaj - tworzone są już na samym starcie programu.

Tak jak zmienna lokalna pamięta swoją wartość pomiędzy kolejnymi wywołaniami, tak pole statyczne klasy pamięta swoją wartość "pomiędzy obiektami". Nie ważne z jakiego obiektu się do niego odwołasz, wartość będzie ta sama, wspólna dla wszystkich obiektów.

olowek a, b, c;  //stworzenie 3 obiektow
a.cena = 10;
cout << b.cena << endl;  //wypisze 10
c.cena = 20;
cout << b.cena << endl;  //wypisze 20

Pola (atrybuty) statyczne obiektu nazywa się czasem polami (atrybutami) klasy. Można się do nich dostać także wtedy, gdy w ogóle nie mamy żadnego obiektu:

olowek a;
a.cena = 10;
cout << a.cena << endl;        //jako pole obiektu, wypisze 10
cout << olowek::cena << endl;  //jako pole klasy, wypisze 10
olowek::cena = 20;             //jako pole klasy
cout << a.cena << endl;        //jako pole obiektu, wypisze 20

Zmienna statyczna musi mieć 'lokalizację'. Samo umieszczenie takiej zmiennej w definicji klasy nie wystarczy.

Zmienna statyczna klasy musi być gdzieś fizycznie umieszczona, w jednym z plików .cpp. W przypadku powyższego przykładu, wygladałoby to tak:

// plik np. olowek.cpp
int olowek::cena = 5.0; //inicjalizacja jest już opcjonalna

Metody

Metody statyczne klasy to metody, które są uruchamiane w kontekście danej klasy, tak jak zwykłe metody są uruchamiane w kontekście konkretnego obiektu. Oznacza to, że o ile zwykłe metody potrzebują obiektu do prawidłowego działania, to metody statyczne - można wywołać bez podawania jakiegokolwiek obiektu. Ma to jednak swoją cenę - metody statyczne mają dostęp jedynie do innych zmiennych statycznych i metod statycznych tej klasy. Przykład:
//....
class przyklad
{
  private:
    int a, b;
    static int c;
  public:
    static void metoda()
    {
      c=10; 
      // b=10;     - błąd! 'b' nie jest statyczne! nie ma do niego dostępu
      // this->a = 10;  - błąd!! w metodach statycznych 'this' nie istnieje!!
    }
};

Wywoływanie:

klasa::metoda();  //wywolanie bez obiektu, wywołanie "na klasie"
obiekt.metoda();  //wywołanie na obiekcie

Powyższe wywołania zachowają się dokładne tak samo. Nawet jeśli podano obiekt, metoda statyczna będzie miała dostęp
jedynie do części statycznej klasy i będzie modyfikowała dane wspólne wszystkim obiektom klasy.

Inne zastosowania

Słowo kluczowe `static` ma jeszcze jedno zastosowanie: pozwala na ukrycie globalnych symboli. Powiedzmy, że mamy w programie dwa pliki .cpp:
//pierwszy.cpp
int zmienna_globalna;

int funkcja()
{   return zmienna_globalna = 5;
}

int druga()
{   funkcja();  //chcemy wywolac funkcje z _tego_ pliku i ustawic _tutejszą_ zmienną na 5
}
//drugi.cpp
int zmienna_globalna;

int funkcja()
{   return zmienna_globalna = 500;
}

int druga();

int main()
{   druga();   //chcemy wywolac funkcje z tego drugiego pliku - ok
     funkcja();  //chcemy wywolac funkcje z _tego_ pliku i ustawic _tutejszą_ zmienną na 500
}

Próba zbudowania takiego programu nie powiedzie się. Kompilacja obu plików przebiegnie poprawnie, natomiast pojawią się błędy fazy linkowania: każdy z tych plikow .cpp twierdzi, że to właśnie on tworzy zmienną globalną zmienna_globalna. Jeśli chcielibyśmy, aby w istocie była to jedna i ta sama zmienna, należałoby się zdecydować który z plików ma być jej właścicielem, a w pozostałych użyć słowa Extern. W tym przypadku jednak, zaszła kolizja nazw. Chcemy aby oba pliki miały swoje oddzielne zmienne globalne oraz swoje własne, różne funkcje funkcja. Tutaj z pomocą przychodzi własnie static. Dodanie go do deklaracji zmiennej globalnej powoduje ukrycie jej przed innymi plikami .cpp.

//pierwszy.cpp
static int zmienna_globalna;

static int funkcja()
{   return zmienna_globalna = 5;
}

int druga()
{   funkcja();  //chcemy wywolac funkcje z _tego_ pliku i ustawic _tutejszą_ zmienną na 5
}
//drugi.cpp
int zmienna_globalna;

int funkcja()
{   return zmienna_globalna = 500;
}

int druga();

int main()
{   funkcja();  //chcemy wywolac funkcje z _tego_ pliku i ustawic _tutejszą_ zmienną na 500
     druga();
}

Po tej modyfikacji, funkcje main oraz funkcja z pierwszego pliku przestaną widzieć symbole zmienna_globalna oraz funkcja z drugiego pliku i kolizja nie wystąpi: main użyje jedynej widocznej - funkcji funkcja z drugiego pliku, analogicznie funkcja z drugiego pliki użyje jedynej widocznej dla siebie zmiennej_globalnej. W pierwszym pliku zaś wszystkie funkcje użyją funkcji i zmiennej ze swojego pliku.

Statyczne zmienne globalne i statyczne funkcje są całkowicie niewidoczne i niedostępne dla nikogo, poza plikiem .cpp w którym zostały zdefiniowane.

2 komentarzy

Super artykuł.
" static allows the compiler to detect whether a function is
unused, so I can remove it."
Co o tym sądzisz ?

Jeśli o czymś zapomniałem to prosze dopisać ewentualnie błędy poprawić :P