Для того, щоб уточнити питання, я б краще класифікувати використання "статичного" ключового слова у трьох різних формах:
(А). змінні
(В). функції
(С). членські змінні / функції класів
пояснення подано нижче для кожного з підзаголовків:
(A) "статичне" ключове слово для змінних
Це може бути трохи хитро, але якщо його пояснити і зрозуміти правильно, це досить просто.
Щоб пояснити це, спочатку дійсно корисно знати про область, тривалість та зв’язок змінних, без яких завжди важко зрозуміти через мутне поняття статичного ключового слова
1. Область застосування : визначає, де у файлі доступна змінна. Вона може бути двох типів: (i) Локальна або Блокова область застосування . (ii) Глобальний обсяг
2. Тривалість : визначає, коли змінна створюється та знищується. Знову це два типи: (i) Тривалість автоматичного зберігання (для змінних, що мають локальну чи блокову область). (ii) Статична тривалість зберігання (для змінних, що мають глобальний діапазон або локальні змінні (у функції або в кодовому блоці) зі статичним специфікатором).
3. Зв'язок : визначає, чи можна отримати зміну (або зв'язати) змінну в іншому файлі. Знову (і на щастя) він має два типи: (i) внутрішній зв'язок
(для змінних, які мають блок-сферу та глобальний обсяг / масштаб файлів / область загального простору імен) (ii) зовнішній зв'язок (для змінних, що мають лише глобальний обсяг / область застосування / Глобальний обсяг простору імен)
Розглянемо приклад нижче для кращого розуміння простих глобальних та локальних змінних (немає локальних змінних зі статичною тривалістю зберігання):
//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
Зараз приходить концепція зв’язку. Коли глобальна змінна, визначена в одному файлі, призначена для використання в іншому файлі, зв'язок змінної відіграє важливу роль.
Зв'язок глобальних змінних визначається ключовими словами: (i) статичні та (ii) зовнішні
(Тепер ви отримаєте пояснення)
статичне ключове слово можна застосувати до змінних з локальною та глобальною сферою, і в обох випадках вони означають різні речі. Я спочатку поясню використання "статичного" ключового слова у змінних із загальною сферою (де я також уточнюю використання ключового слова "екстерн"), а пізніше для тих, що мають локальну область застосування.
1. Статичне ключове слово для змінних із загальним масштабом
Глобальні змінні мають статичну тривалість, тобто вони не виходять за межі, коли конкретний блок коду (наприклад, main ()), в якому він використовується, закінчується. Залежно від зв'язку, до них можна отримати доступ лише в тому самому файлі, де вони оголошені (для статичної глобальної змінної), або поза файлом, навіть поза файлом, у якому вони оголошені (глобальні змінні типу зовнішнього типу)
У випадку глобальної змінної, яка має специфікатор extern, і якщо доступ до цієї змінної знаходиться за межами файлу, в якому вона ініціалізована, вона повинна бути оголошена вперед у файлі, де вона використовується, як і функція повинна бути переадресована оголошено, якщо його визначення знаходиться у файлі, відмінному від того, де воно використовується.
На відміну від цього, якщо глобальна змінна має статичне ключове слово, вона не може бути використана у файлі, поза яким вона була оголошена.
(див. приклад для пояснення)
наприклад:
//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;
}
тепер будь-яка змінна в c ++ може бути або const, або non-const, і для кожного 'const-ness' ми отримуємо два випадки зв'язку c ++ за замовчуванням, якщо жоден не вказаний:
(i) Якщо глобальна змінна non-const, її зв'язок за замовчуванням є зовнішньою, тобто до глобальної змінної non-const можна отримати доступ до іншого .cpp-файлу шляхом прямого оголошення з використанням ключового слова extern (іншими словами, non const global змінні мають зовнішній зв'язок (зі статичною тривалістю курсу)). Також використання ключового слова extern у вихідному файлі, де воно було визначене, є зайвим. У цьому випадку, щоб зробити глобальну змінну non-const недоступною для зовнішнього файлу, використовуйте специфікатор 'static' перед типом змінної .
(ii) Якщо глобальна змінна const, її зв'язок за замовчуванням є статичною , тобто глобальна змінна const не може бути доступна у файлі, відмінному від того, де вона визначена (іншими словами, глобальні змінні const мають внутрішню зв'язок (зі статичною тривалістю) звичайно)). Також використання статичного ключового слова для запобігання доступу до глобальної змінної const в інший файл не є надмірним. Тут, щоб зробити глобальну змінну const мати зовнішню зв'язок, використовуйте специфікатор 'extern' перед типом змінної
Ось підсумок глобальних змінних областей із різними зв'язками
//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
Далі ми досліджуємо, як поводяться вищезгадані глобальні змінні під час доступу до іншого файлу.
//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. Статичне ключове слово для змінних з локальною областю
Оновлення (серпень 2019 року) для статичного ключового слова для змінних в локальному масштабі
Далі це можна розділити на дві категорії:
(i) статичне ключове слово для змінних у функціональному блоці та (ii) статичне ключове слово для змінних у неназваному локальному блоці.
(i) статичне ключове слово для змінних у функціональному блоці.
Раніше я згадував, що змінні з локальною областю мають автоматичну тривалість, тобто вони існують при введенні блоку (будь то нормальний блок, чи це функціональний блок) і перестають існувати, коли блок закінчується, короткий короткий сюжет, змінні з локальною областю мають автоматичну тривалість і автоматичні змінні тривалості (і об'єкти) не мають зв'язку, тобто вони не видно поза кодовим блоком.
Якщо статичний специфікатор застосовується до локальної змінної у функціональному блоці, він змінює тривалість змінної з автоматичної на статичну і її тривалість життя становить всю тривалість програми, що означає, що вона має фіксовану локацію пам'яті і її значення ініціалізується лише один раз перед запуском програми, як зазначено у посиланні на cpp (ініціалізацію не слід плутати з призначенням)
давайте подивимось на приклад.
//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;
}
Дивлячись на вищевказаний критерій статичних локальних змінних та статичних глобальних змінних, можна спробувати запитати, якою може бути різниця між ними. Хоча глобальні змінні доступні в будь-якій точці коду (так само, як і в різній одиниці перекладу залежно від const -ness та extern -ness), статична змінна, визначена у функціональному блоці, не є безпосередньо доступною. Змінна повинна бути повернута значенням функції або посиланням. Продемонструємо це на прикладі:
//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;
}
Більше пояснення щодо вибору статичної глобальної та статичної локальної змінної можна знайти в цій потоці stackoverflow
(ii) статичне ключове слово для змінних в неназваному локальному блоці.
статичні змінні в локальному блоці (а не функціональний блок) не можуть бути доступні за межами блоку, коли локальний блок вийде за межі області. Немає застережень до цього правила.
//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 представив ключове слово, constexpr
яке гарантує оцінку виразу під час компіляції та дозволяє компілятору оптимізувати код. Тепер, якщо значення статичної змінної const у межах області відоме під час компіляції, код оптимізується таким чином, як у constexpr
. Ось невеликий приклад
Я рекомендую читачам також шукати різницю між змінними constexpr
та static const
для змінних у цій потоці stackoverflow . цим завершується моє пояснення статичного ключового слова, застосованого до змінних.
B. "статичне" ключове слово, яке використовується для функцій
з точки зору функцій статичне ключове слово має прямолінійне значення. Тут йдеться про зв'язок функції.
Зазвичай всі функції, оголошені у файлі cpp, за замовчуванням мають зовнішню зв'язок, тобто функція, визначена в одному файлі, може використовуватися в іншому файлі cpp шляхом прямого оголошення.
використання статичного ключового слова перед тим, як оголошення функції обмежує його зв'язок із внутрішнім , тобто статична функція не може використовуватися у файлі поза його визначенням.
C. Ключове слово Staitc, яке використовується для змінних членів та функцій класів
1. "статичне" ключове слово для змінних членів класів
Почніть безпосередньо з прикладу
#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;
}
У цьому прикладі статична змінна m_designNum зберігає своє значення, і ця змінна одного приватного члена (оскільки є статичною) поділяється в / в з усіма змінними об'єкта типу DesignNumber
Також, як і інші змінні члена, статичні змінні елемента класу не асоціюються з жодним об'єктом класу, що демонструється друком будь-якого номера в головній функції
const vs non-const статичні змінні члена в класі
(i) статичні змінні елемента нестандартних класів
У попередньому прикладі статичні члени (як державні, так і приватні) були неконстантами. Стандарт ISO забороняє нестандартні статичні члени ініціалізуватися у класі. Отже, як і в попередньому прикладі, вони повинні бути ініціалізовані після визначення класу, із застереженням, що статичне ключове слово потрібно опустити
(ii) const-статичні змінні члена класу
це просто і відповідає умові ініціалізації інших змінних const-членів, тобто змінних const статичних членів класу можна ініціалізувати в точці оголошення, і вони можуть бути ініціалізовані в кінці декларації класу з одним застереженням, що ключове слово const потрібно додати до статичного члена при ініціалізації після визначення класу.
Проте я рекомендую ініціалізувати const статичні змінні члена в точці декларування. Це поєднується зі стандартною умовою C ++ і робить код більш чистим
для отримання додаткових прикладів статичних змінних членів у класі шукайте наступне посилання від learncpp.com
http://www.learncpp.com/cpp-tutorial/811-static-member-variables/
2. "статичне" ключове слово для функції членів класів
Подібно до змінних членів класів можуть бути статичними, так можуть бути і членські функції класів. Нормальні функції членів класів завжди пов'язані з об'єктом типу класу. На відміну від цього, статичні функції членів класу не пов'язані з жодним об'єктом класу, тобто вони не мають * цього вказівника.
По-друге, оскільки функції статичного члена класу не мають * цього вказівника, їх можна викликати, використовуючи ім’я класу та оператор роздільної здатності основної функції (ClassName :: functionName ();)
По-третє, статичні функції члена класу можуть отримувати доступ лише до статичних змінних класу класу, оскільки нестатичні змінні елементи класу повинні належати об'єкту класу.
Щоб отримати додаткові приклади статичних функцій членів у класі, перегляньте наступне посилання від learncpp.com
http://www.learncpp.com/cpp-tutorial/812-static-member-functions/