Aby wyjaśnić pytanie, wolę kategoryzować użycie słowa kluczowego „statycznego” w trzech różnych formach:
(ZA). zmienne
(B). Funkcje
(DO). zmienne składowe / funkcje klas
wyjaśnienie poniżej znajduje się dla każdego z podtytułów:
(A) słowo kluczowe „static” dla zmiennych
Ten może być trochę trudny, ale jeśli zostanie odpowiednio wyjaśniony i zrozumiany, jest dość prosty.
Aby to wyjaśnić, po pierwsze, naprawdę warto wiedzieć o zakresie, czasie trwania i powiązaniu zmiennych, bez których rzeczy zawsze trudno jest dostrzec przez mętną koncepcję standardowego słowa kluczowego
1. Zakres : określa, gdzie w pliku zmienna jest dostępna. Może być dwojakiego rodzaju: (i) Lokalny lub Blokowy . (ii) Globalny zakres
2. Czas trwania : określa, kiedy zmienna jest tworzona i niszczona. Ponownie jest on dwojakiego rodzaju: (i) Automatyczny czas przechowywania (dla zmiennych o zasięgu lokalnym lub blokowym). (ii) Statyczny czas przechowywania (dla zmiennych o zasięgu globalnym lub zmiennych lokalnych (w funkcji lub w bloku kodu) ze specyfikatorem statycznym ).
3. Łączenie : Określa, czy można uzyskać dostęp do zmiennej (lub połączyć ją) w innym pliku. Ponownie (i na szczęście) jest on dwojakiego rodzaju: (i) Wewnętrzne powiązanie
(dla zmiennych mających zakres bloku i zakres globalny / zakres pliku / zakres globalnej przestrzeni nazw) (ii) Połączenie zewnętrzne (dla zmiennych mających tylko zakres globalny / zakres pliku / Globalny zakres przestrzeni nazw)
Odwołajmy się do poniższego przykładu, aby lepiej zrozumieć zwykłe zmienne globalne i lokalne (brak zmiennych lokalnych ze statycznym czasem przechowywania):
//main file
#include <iostream>
int global_var1; //has global scope
const global_var2(1.618); //has global scope
int main()
{
//these variables are local to the block main.
//they have automatic duration, i.e, they are created when the main() is
// executed and destroyed, when main goes out of scope
int local_var1(23);
const double local_var2(3.14);
{
/* this is yet another block, all variables declared within this block are
have local scope limited within this block. */
// all variables declared within this block too have automatic duration, i.e,
/*they are created at the point of definition within this block,
and destroyed as soon as this block ends */
char block_char1;
int local_var1(32) //NOTE: this has been re-declared within the block,
//it shadows the local_var1 declared outside
std::cout << local_var1 <<"\n"; //prints 32
}//end of block
//local_var1 declared inside goes out of scope
std::cout << local_var1 << "\n"; //prints 23
global_var1 = 29; //global_var1 has been declared outside main (global scope)
std::cout << global_var1 << "\n"; //prints 29
std::cout << global_var2 << "\n"; //prints 1.618
return 0;
} //local_var1, local_var2 go out of scope as main ends
//global_var1, global_var2 go out of scope as the program terminates
//(in this case program ends with end of main, so both local and global
//variable go out of scope together
Teraz pojawia się koncepcja powiązania. Gdy zmienna globalna zdefiniowana w jednym pliku ma być używana w innym pliku, powiązanie zmiennej odgrywa ważną rolę.
Powiązanie zmiennych globalnych określają słowa kluczowe: (i) statyczny i (ii) zewnętrzny
(Teraz dostajesz wyjaśnienie)
statyczne słowo kluczowe można zastosować do zmiennych o zasięgu lokalnym i globalnym, aw obu przypadkach oznaczają one różne rzeczy. Najpierw wyjaśnię użycie słowa kluczowego „static” w zmiennych o zasięgu globalnym (gdzie wyjaśnię również użycie słowa kluczowego „extern”), a później tych o zasięgu lokalnym.
1. Statyczne słowo kluczowe dla zmiennych o zasięgu globalnym
Zmienne globalne mają statyczny czas trwania, co oznacza, że nie wykraczają poza zakres, gdy kończy się określony blok kodu (np. Main ()), w którym jest używany. W zależności od powiązania można uzyskać do nich dostęp tylko w tym samym pliku, w którym są zadeklarowane (dla statycznej zmiennej globalnej), lub poza plikiem, nawet poza plikiem, w którym zostały zadeklarowane (zmienne globalne typu zewnętrznego)
W przypadku zmiennej globalnej mającej specyfikator zewnętrzny i jeśli dostęp do tej zmiennej jest uzyskiwany poza plikiem, w którym została zainicjowana, należy ją zadeklarować w pliku, w którym jest używana, tak jak funkcja musi być przekazana do przodu zadeklarowane, jeśli jego definicja znajduje się w pliku innym niż miejsce, w którym jest używana.
Natomiast jeśli zmienna globalna ma słowo kluczowe static, nie można jej użyć w pliku, poza którym została zadeklarowana.
(patrz wyjaśnienie poniżej)
na przykład:
//main2.cpp
static int global_var3 = 23; /*static global variable, cannot be
accessed in anyother file */
extern double global_var4 = 71; /*can be accessed outside this file linked to main2.cpp */
int main() { return 0; }
main3.cpp
//main3.cpp
#include <iostream>
int main()
{
extern int gloabl_var4; /*this variable refers to the gloabal_var4
defined in the main2.cpp file */
std::cout << global_var4 << "\n"; //prints 71;
return 0;
}
teraz dowolna zmienna w c ++ może być stała lub nie-stała i dla każdej „const-ness” otrzymujemy dwa przypadki domyślnego połączenia c ++, w przypadku gdy nie zostanie określona żadna:
(i) Jeśli zmienna globalna nie jest stała, jej łączenie jest domyślnie zewnętrzne , tj. do niestałej zmiennej globalnej można uzyskać dostęp w innym pliku .cpp poprzez deklarację przesyłania dalej za pomocą słowa kluczowego extern (innymi słowy, niestała globalna zmienne mają powiązanie zewnętrzne (oczywiście ze statycznym czasem trwania)). Również użycie słowa kluczowego extern w oryginalnym pliku, w którym został zdefiniowany, jest zbędne. W takim przypadku, aby stała zmienna globalna stała się niedostępna dla pliku zewnętrznego, należy użyć specyfikatora „static” przed typem zmiennej .
(ii) Jeśli zmienna globalna jest stała, jej łączenie jest domyślnie statyczne , tj. stała zmienna globalna nie może być dostępna w pliku innym niż tam, gdzie została zdefiniowana (innymi słowy, stałe zmienne globalne mają wewnętrzne powiązanie (z czasem trwania statycznym oczywiście)). Również użycie słowa kluczowego static, aby uniemożliwić dostęp do stałej zmiennej globalnej w innym pliku, jest zbędne. Tutaj, aby stała zmienna globalna miała zewnętrzny link, użyj specyfikatora „extern” przed typem zmiennej
Oto podsumowanie globalnych zmiennych zasięgu z różnymi powiązaniami
//globalVariables1.cpp
// defining uninitialized vairbles
int globalVar1; // uninitialized global variable with external linkage
static int globalVar2; // uninitialized global variable with internal linkage
const int globalVar3; // error, since const variables must be initialized upon declaration
const int globalVar4 = 23; //correct, but with static linkage (cannot be accessed outside the file where it has been declared*/
extern const double globalVar5 = 1.57; //this const variable ca be accessed outside the file where it has been declared
Następnie badamy, jak zachowują się powyższe zmienne globalne, gdy są dostępne w innym pliku.
//using_globalVariables1.cpp (eg for the usage of global variables above)
// Forward declaration via extern keyword:
extern int globalVar1; // correct since globalVar1 is not a const or static
extern int globalVar2; //incorrect since globalVar2 has internal linkage
extern const int globalVar4; /* incorrect since globalVar4 has no extern
specifier, limited to internal linkage by
default (static specifier for const variables) */
extern const double globalVar5; /*correct since in the previous file, it
has extern specifier, no need to initialize the
const variable here, since it has already been
legitimately defined perviously */
2. Statyczne słowo kluczowe dla zmiennych o zasięgu lokalnym
Aktualizacje (sierpień 2019 r.) Statycznego słowa kluczowego dla zmiennych w zasięgu lokalnym
Można to dodatkowo podzielić na dwie kategorie:
(i) słowo kluczowe static dla zmiennych w bloku funkcyjnym oraz (ii) słowo kluczowe static dla zmiennych w nienazwanym bloku lokalnym.
(i) słowo kluczowe static dla zmiennych w bloku funkcyjnym.
Wcześniej wspomniałem, że zmienne o zasięgu lokalnym mają automatyczny czas trwania, tj. Powstają, gdy blok jest wprowadzany (czy to zwykły blok, czy to blok funkcyjny), i przestają istnieć, gdy blok się kończy, krótko mówiąc, zmienne z zasięgiem lokalnym mają automatyczny czas trwania i automatyczne zmienne czasu trwania (i obiekty) nie mają powiązania, co oznacza, że nie są widoczne poza blokiem kodu.
Jeśli specyfikator statyczny jest zastosowany do zmiennej lokalnej w bloku funkcyjnym, zmienia on czas trwania zmiennej z automatycznej na statyczną, a jej czas życia to cały czas trwania programu, co oznacza, że ma on stałe położenie w pamięci, a jego wartość jest inicjowana tylko raz przed uruchomieniem programu, jak wspomniano w dokumentacji cpp (inicjalizacji nie należy mylić z przypisaniem)
spójrzmy na przykład.
//localVarDemo1.cpp
int localNextID()
{
int tempID = 1; //tempID created here
return tempID++; //copy of tempID returned and tempID incremented to 2
} //tempID destroyed here, hence value of tempID lost
int newNextID()
{
static int newID = 0;//newID has static duration, with internal linkage
return newID++; //copy of newID returned and newID incremented by 1
} //newID doesn't get destroyed here :-)
int main()
{
int employeeID1 = localNextID(); //employeeID1 = 1
int employeeID2 = localNextID(); // employeeID2 = 1 again (not desired)
int employeeID3 = newNextID(); //employeeID3 = 0;
int employeeID4 = newNextID(); //employeeID4 = 1;
int employeeID5 = newNextID(); //employeeID5 = 2;
return 0;
}
Patrząc na powyższe kryterium dla statycznych zmiennych lokalnych i statycznych zmiennych globalnych, można pokusić się o pytanie, jaka może być różnica między nimi. Natomiast zmienne globalne są dostępne w dowolnym momencie w ciągu kodu (w samo jak jednostka różni się w zależności od tłumaczenia const -ness i extern -ness), zmienna statyczna zdefiniowana w bloku funkcyjnego nie jest bezpośrednio dostępne. Zmienna musi zostać zwrócona przez wartość funkcji lub odwołanie. Pokażmy to na przykładzie:
//localVarDemo2.cpp
//static storage duration with global scope
//note this variable can be accessed from outside the file
//in a different compilation unit by using `extern` specifier
//which might not be desirable for certain use case.
static int globalId = 0;
int newNextID()
{
static int newID = 0;//newID has static duration, with internal linkage
return newID++; //copy of newID returned and newID incremented by 1
} //newID doesn't get destroyed here
int main()
{
//since globalId is accessible we use it directly
const int globalEmployee1Id = globalId++; //globalEmployeeId1 = 0;
const int globalEmployee2Id = globalId++; //globalEmployeeId1 = 1;
//const int employeeID1 = newID++; //this will lead to compilation error since newID++ is not accessible direcly.
int employeeID2 = newNextID(); //employeeID3 = 0;
int employeeID2 = newNextID(); //employeeID3 = 1;
return 0;
}
Więcej wyjaśnień na temat wyboru statycznej globalnej i statycznej zmiennej lokalnej można znaleźć w tym wątku przepływu stosu
(ii) statyczne słowo kluczowe dla zmiennych w nienazwanym bloku lokalnym.
do zmiennych statycznych w bloku lokalnym (nie bloku funkcyjnym) nie można uzyskać dostępu poza blokiem, gdy blok lokalny wykracza poza zakres. Żadnych zastrzeżeń do tej zasady.
//localVarDemo3.cpp
int main()
{
{
const static int static_local_scoped_variable {99};
}//static_local_scoped_variable goes out of scope
//the line below causes compilation error
//do_something is an arbitrary function
do_something(static_local_scoped_variable);
return 0;
}
C ++ 11 wprowadził słowo kluczowe, constexpr
które gwarantuje ocenę wyrażenia w czasie kompilacji i pozwala kompilatorowi zoptymalizować kod. Teraz, jeśli wartość stałej stałej statycznej w zakresie jest znana w czasie kompilacji, kod jest optymalizowany w sposób podobny do tego z constexpr
. Oto mały przykład
Polecam także czytelnikom, aby sprawdzili różnicę między zmiennymi constexpr
i static const
dla zmiennych w tym wątku przepełnienia stosu . to kończy moje wyjaśnienie statycznego słowa kluczowego stosowanego do zmiennych.
B. słowo kluczowe „static” używane dla funkcji
pod względem funkcji słowo kluczowe static ma bezpośrednie znaczenie. Tutaj odnosi się do powiązania funkcji
Zwykle wszystkie funkcje zadeklarowane w pliku cpp mają domyślnie powiązanie zewnętrzne, tj. Funkcja zdefiniowana w jednym pliku może być użyta w innym pliku cpp poprzez deklarację przesyłania dalej.
użycie statycznego słowa kluczowego przed deklaracją funkcji ogranicza jego powiązanie z wewnętrznym , tzn. funkcja statyczna nie może być używana w pliku poza jego definicją.
C. Staitc Słowo kluczowe używane do zmiennych składowych i funkcji klas
1. Słowo kluczowe „static” dla zmiennych składowych klas
Zaczynam bezpośrednio od przykładu tutaj
#include <iostream>
class DesignNumber
{
private:
static int m_designNum; //design number
int m_iteration; // number of iterations performed for the design
public:
DesignNumber() { } //default constructor
int getItrNum() //get the iteration number of design
{
m_iteration = m_designNum++;
return m_iteration;
}
static int m_anyNumber; //public static variable
};
int DesignNumber::m_designNum = 0; // starting with design id = 0
// note : no need of static keyword here
//causes compiler error if static keyword used
int DesignNumber::m_anyNumber = 99; /* initialization of inclass public
static member */
enter code here
int main()
{
DesignNumber firstDesign, secondDesign, thirdDesign;
std::cout << firstDesign.getItrNum() << "\n"; //prints 0
std::cout << secondDesign.getItrNum() << "\n"; //prints 1
std::cout << thirdDesign.getItrNum() << "\n"; //prints 2
std::cout << DesignNumber::m_anyNumber++ << "\n"; /* no object
associated with m_anyNumber */
std::cout << DesignNumber::m_anyNumber++ << "\n"; //prints 100
std::cout << DesignNumber::m_anyNumber++ << "\n"; //prints 101
return 0;
}
W tym przykładzie zmienna statyczna m_designNum zachowuje swoją wartość, a ta pojedyncza zmienna prywatna (ponieważ jest statyczna) jest współużytkowana przez wszystkie zmienne typu obiektu DesignNumber
Podobnie jak inne zmienne składowe, statyczne zmienne składowe klasy nie są powiązane z żadnym obiektem klasy, o czym świadczy wydrukowanie dowolnej liczby w funkcji głównej
const vs niestałe statyczne zmienne składowe w klasie
(i) niestacjonarne zmienne klasy członka
W poprzednim przykładzie statyczne elementy (publiczne i prywatne) nie były stałymi. Norma ISO zabrania inicjowania elementów niestałych w klasie. Dlatego, podobnie jak w poprzednim przykładzie, należy je zainicjować po definicji klasy, z zastrzeżeniem, że słowo kluczowe static musi zostać pominięte
(ii) const-static zmienne składowe klasy
jest to proste i zgodne z konwencją inicjalizacji innych zmiennych const składowych, tzn. stałe zmienne składowe const klasy mogą być inicjalizowane w punkcie deklaracji i mogą być inicjalizowane na końcu deklaracji klasy z jednym zastrzeżeniem, że słowo kluczowe const musi zostać dodane do elementu statycznego podczas inicjalizacji po definicji klasy.
Poleciłbym jednak zainicjować stałe statyczne zmienne składowe w punkcie deklaracji. Jest to zgodne ze standardową konwencją C ++ i sprawia, że kod wygląda na czystszy
Aby uzyskać więcej przykładów statycznych zmiennych składowych w klasie, wyszukaj następujący link z learncpp.com
http://www.learncpp.com/cpp-tutorial/811-static-member-variables/
2. Słowo kluczowe „static” dla funkcji składowej klas
Podobnie jak zmienne składowe klas mogą być statyczne, podobnie jak składowe funkcje klas. Normalne funkcje składowe klas są zawsze powiązane z obiektem typu klasy. Natomiast statyczne funkcje składowe klasy nie są powiązane z żadnym obiektem klasy, tj. Nie mają * tego wskaźnika.
Po drugie, ponieważ statyczne funkcje składowe klasy nie mają * tego wskaźnika, można je wywoływać, używając nazwy klasy i operatora rozpoznawania zakresu w funkcji głównej (ClassName :: functionName ();)
Po trzecie, statyczne funkcje składowe klasy mogą uzyskiwać dostęp tylko do statycznych zmiennych składowych klasy, ponieważ niestatyczne zmienne składowe klasy muszą należeć do obiektu klasy.
Aby uzyskać więcej przykładów statycznych funkcji składowych w klasie, wyszukaj poniższy link z learncpp.com
http://www.learncpp.com/cpp-tutorial/812-static-member-functions/