Ключевое слово static и его различные применения в C++
Ключевое слово static
это тот, который имеет несколько значений в C++, который я нахожу очень запутанным, и я никогда не могу думать о том, как это на самом деле должно работать.
Из того, что я понимаю, есть static
продолжительность хранения, что означает, что она длится в течение всей жизни программы в случае глобального, но когда вы говорите о локальном, это означает, что он по умолчанию инициализируется нулем.
Стандарт C++ говорит это для членов класса данных с ключевым словом static
:
3.7.1 Статическая продолжительность хранения [basic.stc.static]
3 Ключевое слово static может использоваться для объявления локальной переменной со статической продолжительностью хранения.
4 Ключевое слово static, примененное к члену данных класса в определении класса, дает длительность хранения статического члена данных.
Что это значит с локальной переменной? Это локальная переменная функции? Потому что есть также то, что когда вы объявляете функцию локальной как static
что он инициализируется только один раз, при первом входе в эту функцию.
Это также говорит только о продолжительности хранения в отношении участников класса, что касается того, что оно не является специфичным для экземпляра, это также свойство static
нет? Или это продолжительность хранения?
Теперь насчет случая с static
а объем файла? Все ли глобальные переменные имеют статическую длительность хранения по умолчанию? Следующее (из раздела 3.7.1), кажется, указывает на это:
1 Все переменные, которые не имеют динамической длительности хранения, не имеют длительности хранения потока и не являются локальными, имеют статическую длительность хранения. Хранение для этих объектов должно продолжаться в течение всей программы (3.6.2, 3.6.3)
Как static
относятся к связи переменной?
Весь этот static
ключевое слово просто сбивает с толку, может кто-то прояснить различные варианты использования английского языка, а также сказать мне, когда инициализировать static
член класса?
9 ответов
Переменные:
static
переменные существуют для "времени жизни" единицы перевода, в которой она определена, и:
- Если он находится в области имен (то есть вне функций и классов), то к нему нельзя получить доступ из любого другого модуля перевода. Это известно как "внутренняя связь" или "статическая продолжительность хранения". (Не делайте этого в заголовках, это просто ужасная идея, в результате вы получите отдельную переменную в каждой единице перевода, что безумно запутанно)
- Если это переменная в функции, к ней нельзя получить доступ извне функции, как и к любой другой локальной переменной. (это местные они упоминали)
- члены класса не имеют ограниченной области видимости из-за
static
, но может быть адресован как из класса, так и из экземпляра (например,std::string::npos
). [Примечание: вы можете объявить статические члены в классе, но обычно они все равно должны быть определены в модуле перевода (файл cpp), и поэтому в каждом классе есть только один]
местоположения как код:
static std::string namespaceScope = "Hello";
void foo() {
static std::string functionScope= "World";
}
struct A {
static std::string classScope = "!";
};
Перед выполнением любой функции в модуле перевода (возможно, после main
начало выполнения), переменные со статической продолжительностью хранения (область пространства имен) в этом модуле перевода будут "постоянно инициализированы" (для constexpr
где это возможно, или ноль в противном случае), а затем нелокальные значения должным образом "динамически инициализируются" в том порядке, в котором они определены в единице перевода (для таких вещей, как std::string="HI";
это не constexpr
). Наконец, локальные статические функции будут инициализированы, когда в первый раз выполнение "достигнет" строки, где они объявлены. Все static
Все переменные уничтожаются в обратном порядке инициализации.
Самый простой способ сделать все это правильно, это сделать все статические переменные, которые не являются constexpr
инициализируется в функции static localals, которая гарантирует, что все ваши статические / глобальные переменные инициализируются должным образом, когда вы пытаетесь использовать их независимо от того, что, таким образом, предотвращает фиаско статического порядка инициализации.
T& get_global() {
static T global = initial_value();
return global;
}
Будьте осторожны, потому что, когда спецификация говорит, что переменные области пространства имен по умолчанию имеют "статическую длительность хранения", они означают бит "время жизни единицы перевода", но это не означает, что к нему нельзя получить доступ вне файла.
функции
Значительно более простой, static
часто используется в качестве функции-члена класса и очень редко используется для отдельно стоящей функции.
Статическая функция-член отличается от обычной функции-члена тем, что ее можно вызывать без экземпляра класса, и, поскольку она не имеет экземпляра, она не может получить доступ к нестатическим членам класса. Статические переменные полезны, когда вы хотите иметь функцию для класса, который определенно абсолютно не ссылается на элементы экземпляра, или для управления static
переменные-члены.
struct A {
A() {++A_count;}
A(const A&) {++A_count;}
A(A&&) {++A_count;}
~A() {--A_count;}
static int get_count() {return A_count;}
private:
static int A_count;
}
int main() {
A var;
int c0 = var.get_count(); //some compilers give a warning, but it's ok.
int c1 = A::get_count(); //normal way
}
static
free-function означает, что на функцию не будет ссылаться ни одна другая единица перевода, и, таким образом, компоновщик может полностью ее игнорировать. Это имеет небольшое количество целей:
- Может использоваться в файле cpp, чтобы гарантировать, что функция никогда не используется из любого другого файла.
- Может быть помещен в заголовок, и каждый файл будет иметь свою собственную копию функции. Не полезно, так как inline делает почти то же самое.
- Ускоряет время соединения за счет сокращения работы
- Можно поместить функцию с одинаковым именем в каждую единицу перевода, и все они могут делать разные вещи. Например, вы могли бы поставить
static void log(const char*) {}
в каждом файле cpp, и каждый из них может войти в систему по-своему.
Чтобы прояснить вопрос, я бы предпочел классифицировать использование ключевого слова static в трех разных формах:
(А). переменные
(В). функции
(С). переменные-члены / функции классов
объяснение следует ниже для каждого из подзаголовков:
(A) "статическое" ключевое слово для переменных
Это может быть немного сложнее, однако, если объяснить и правильно понять, это довольно просто.
Чтобы объяснить это, во-первых, действительно полезно узнать о области действия, продолжительности и связях переменных, без которых вещи всегда трудно увидеть сквозь мутную концепцию staic ключевого слова.
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
Теперь приходит концепция Linkage. Когда глобальная переменная, определенная в одном файле, предназначена для использования в другом файле, связь с переменной играет важную роль.
Связывание глобальных переменных задается ключевыми словами: (i) статическая и (ii) внешняя
(Теперь вы получите объяснение;-))
Ключевое слово static может применяться к переменным с локальной и глобальной областью действия, и в обоих случаях они означают разные вещи. Сначала я объясню использование ключевого слова "static" в переменных с глобальной областью действия (где я также разъясню использование ключевого слова "extern"), а позже - для тех, которые имеют локальную область действия.
1. Статическое ключевое слово для переменных с глобальной областью видимости
Глобальные переменные имеют статическую длительность, то есть они не выходят за рамки, когда заканчивается конкретный блок кода (например, main()), в котором он используется. В зависимости от связи, к ним можно получить доступ только в том же файле, в котором они объявлены (для статической глобальной переменной), или вне файла, даже вне файла, в котором они объявлены (глобальные переменные типа extern)
В случае, когда глобальная переменная имеет спецификатор extern, и если к этой переменной обращаются вне файла, в котором она была инициализирована, она должна быть объявлена вперед в файле, где она используется, точно так же, как функция должна быть вперед объявляется, если его определение находится в файле, отличном от того, где он используется.
Напротив, если глобальная переменная имеет ключевое слово static, ее нельзя использовать в файле, за пределами которого она была объявлена.
(см. пример ниже для пояснения)
например:
//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++ может быть как константной, так и неконстантной, и для каждой "константности" мы получаем два случая связи по умолчанию с ++, в случае, если ни одна не указана:
(i) Если глобальная переменная не является константной, по умолчанию ее связь является внешней, то есть к неконстантной глобальной переменной можно получить доступ в другом файле.cpp путем предварительного объявления с использованием ключевого слова extern (другими словами, неконстантной глобальной переменные имеют внешнюю связь (со статической продолжительностью, конечно)). Также избыточное использование ключевого слова extern в исходном файле, в котором оно было определено. В этом случае, чтобы сделать неконстантную глобальную переменную недоступной для внешнего файла, используйте спецификатор "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. Статическое ключевое слово для переменных с локальной областью действия
Ранее я упоминал, что переменные с локальной областью видимости имеют автоматическую длительность, то есть они начинают существовать при вводе блока (будь то обычный блок, будь то функциональный блок) и перестают существовать, когда блок заканчивается, короче говоря, переменные с локальной областью действия имеют автоматическую длительность, а автоматические переменные продолжительности (и объекты) не имеют связи, означая, что они не видны вне блока кода.
Если статический спецификатор применяется к локальной переменной в блоке, он меняет продолжительность переменной с автоматической на статическую, а ее срок службы равен всей продолжительности программы, что означает, что она имеет фиксированное расположение в памяти, а ее значение инициализируется только один раз. до запуска программы, как указано в справочнике cpp (инициализация не должна быть перепутана с присваиванием)
Давайте посмотрим на пример.
//localVarDemo.cpp
#include <iostream>
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 = nextID(); //employeeID1 = 1
int employeeID2 = nextID(); // employeeID2 = 1 again (not desired)
int employeeID3 = newNextID(); //employeeID3 = 0;
int employeeID4 = newNextID(); //employeeID4 = 1;
int employeeID5 = newNextID(); //employeeID5 = 2;
return 0;
}
На этом мое объяснение ключевого слова static применяется к переменным. pheww!!!
B. ключевое слово static для функций
в терминах функций ключевое слово static имеет прямое значение. Здесь это относится к связыванию функции. Обычно все функции, объявленные в файле 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.
Также как и другие переменные-члены, статические переменные-члены класса не связаны ни с одним объектом класса, что демонстрируется печатью anyNumber в основной функции.
const против неконстантных статических переменных-членов в классе
(i) статические переменные-члены неконстантного класса. В предыдущем примере статические члены (как публичные, так и частные) были неконстантными. Стандарт ISO запрещает инициализацию неконстантных статических элементов в классе. Следовательно, как и в предыдущем примере, они должны быть инициализированы после определения класса с оговоркой, что статическое ключевое слово должно быть опущено
(ii) const-статические переменные-члены класса это просто и соответствует соглашению об инициализации других переменных-членов const, то есть постоянные статические переменные-члены класса могут быть инициализированы в точке объявления, и они могут быть инициализированы в конце объявления класса с одним предупреждением о том, что ключевое слово const необходимо добавить к статическому члену при инициализации после определения класса.
Однако я бы порекомендовал инициализировать статические переменные-члены const в точке объявления. Это соответствует стандартному соглашению C++ и делает код более чистым
Дополнительные примеры статических переменных-членов в классе можно найти по следующей ссылке на веб- сайте learncpp.com http://www.learncpp.com/cpp-tutorial/811-static-member-variables/
2. ключевое слово "static" для функции-члена классов
Как переменные-члены классов могут быть статическими, так и функции-члены классов. Обычные функции-члены классов всегда связаны с объектом типа класса. Напротив, статические функции-члены класса не связаны ни с одним объектом класса, т. Е. У них нет * этого указателя.
Во-вторых, поскольку статические функции-члены класса не имеют * этого указателя, их можно вызывать с помощью оператора разрешения имени и области видимости в основной функции (ClassName::functionName();)
В-третьих, статические функции-члены класса могут обращаться только к статическим переменным-членам класса, поскольку нестатические переменные-члены класса должны принадлежать объекту класса.
Дополнительные примеры статических функций-членов в классе можно найти по следующей ссылке с learncpp.com.
http://www.learncpp.com/cpp-tutorial/812-static-member-functions/
Статическая продолжительность хранения означает, что переменная находится в одном и том же месте в памяти в течение всего времени жизни программы.
Связь является ортогональной к этому.
Я думаю, что это самое важное различие, которое вы можете сделать. Понять это и все остальное, а также запомнить это должно быть легко (не обращаясь непосредственно к @Tony, но к тому, кто бы мог прочитать это в будущем).
Ключевое слово static
может использоваться для обозначения внутренней связи и статического хранилища, но по сути они разные.
Что это значит с локальной переменной? Это локальная переменная функции?
Да. Независимо от того, когда переменная инициализируется (при первом вызове функции и когда путь выполнения достигает точки объявления), она будет находиться в одном и том же месте в памяти на протяжении всей жизни программы. В этом случае, static
дает ему статическое хранилище.
А как насчет случая со статической и файловой областью? Все ли глобальные переменные имеют статическую длительность хранения по умолчанию?
Да, все глобальные переменные по определению имеют статическую продолжительность хранения (теперь, когда мы выяснили, что это значит). Но переменные в пространстве имен не объявляются с static
потому что это дало бы им внутреннюю связь, поэтому переменная на единицу перевода.
Как статические связаны со связью переменной?
Он дает внутреннюю связь переменных пространства имен. Он дает членам и локальным переменным статическую продолжительность хранения.
Давайте расширим все это:
//
static int x; //internal linkage
//non-static storage - each translation unit will have its own copy of x
//NOT A TRUE GLOBAL!
int y; //static storage duration (can be used with extern)
//actual global
//external linkage
struct X
{
static int x; //static storage duration - shared between classes
};
void foo()
{
static int x; //static storage duration - shared between calls
}
Это целое статическое ключевое слово совершенно сбивает с толку
Определенно, если вы не знакомы с этим.:) Стараясь не добавлять новые ключевые слова в язык, комитет повторно использовал это, IMO, для этого - путаница. Он используется для обозначения разных вещей (я бы сказал, возможно, противоположных вещей).
Это на самом деле довольно просто. Если вы объявляете переменную как статическую в области действия функции, ее значение сохраняется между последовательными вызовами этой функции. Так:
int myFun()
{
static int i=5;
i++;
return i;
}
int main()
{
printf("%d", myFun());
printf("%d", myFun());
printf("%d", myFun());
}
покажет 678
вместо 666
, потому что он запоминает увеличенное значение.
Что касается статических членов, они сохраняют свое значение в экземплярах класса. Итак, следующий код:
struct A
{
static int a;
};
int main()
{
A first;
A second;
first.a = 3;
second.a = 4;
printf("%d", first.a);
}
выведет 4, потому что first.a и second.a по сути одна и та же переменная. Что касается инициализации, см. Этот вопрос.
Когда вы объявляете static
переменная в области видимости файла, то эта переменная доступна только в этом конкретном файле (технически, модуль перевода *, но давайте не будем слишком усложнять это). Например:
a.cpp
static int x = 7;
void printax()
{
cout << "from a.cpp: x=" << x << endl;
}
b.cpp
static int x = 9;
void printbx()
{
cout << "from b.cpp: x=" << x << endl;
}
main.cpp:
int main(int, char **)
{
printax(); // Will print 7
printbx(); // Will print 9
return 0;
}
Для локальной переменной static
означает, что переменная будет инициализирована нулями и сохранит свое значение между вызовами:
unsigned int powersoftwo()
{
static unsigned lastpow;
if(lastpow == 0)
lastpow = 1;
else
lastpow *= 2;
return lastpow;
}
int main(int, char **)
{
for(int i = 0; i != 10; i++)
cout << "2^" << i << " = " << powersoftwo() << endl;
}
Для переменных класса это означает, что существует только один экземпляр этой переменной, который является общим для всех членов этого класса. В зависимости от прав доступа к переменной можно обращаться извне класса, используя его полное имя.
class Test
{
private:
static char *xxx;
public:
static int yyy;
public:
Test()
{
cout << this << "The static class variable xxx is at address "
<< static_cast<void *>(xxx) << endl;
cout << this << "The static class variable yyy is at address "
<< static_cast<void *>(&y) << endl;
}
};
// Necessary for static class variables.
char *Test::xxx = "I'm Triple X!";
int Test::yyy = 0;
int main(int, char **)
{
Test t1;
Test t2;
Test::yyy = 666;
Test t3;
};
Маркировка неклассовой функции как static
делает функцию доступной только из этого файла и недоступной из других файлов.
a.cpp
static void printfilename()
{ // this is the printfilename from a.cpp -
// it can't be accessed from any other file
cout << "this is a.cpp" << endl;
}
b.cpp
static void printfilename()
{ // this is the printfilename from b.cpp -
// it can't be accessed from any other file
cout << "this is b.cpp" << endl;
}
Для функций членов класса, помечая их как static
означает, что функцию не нужно вызывать для конкретного экземпляра объекта (т.е. она не имеет this
указатель).
class Test
{
private:
static int count;
public:
static int GetTestCount()
{
return count;
};
Test()
{
cout << this << "Created an instance of Test" << endl;
count++;
}
~Test()
{
cout << this << "Destroyed an instance of Test" << endl;
count--;
}
};
int Test::count = 0;
int main(int, char **)
{
Test *arr[10] = { NULL };
for(int i = 0; i != 10; i++)
arr[i] = new Test();
cout << "There are " << Test::GetTestCount() << " instances of the Test class!" << endl;
// now, delete them all except the first and last!
for(int i = 1; i != 9; i++)
delete arr[i];
cout << "There are " << Test::GetTestCount() << " instances of the Test class!" << endl;
delete arr[0];
cout << "There are " << Test::GetTestCount() << " instances of the Test class!" << endl;
delete arr[9];
cout << "There are " << Test::GetTestCount() << " instances of the Test class!" << endl;
return 0;
}
Статические переменные совместно используются каждым экземпляром класса, а не каждому классу, имеющему свою собственную переменную.
class MyClass
{
public:
int myVar;
static int myStaticVar;
};
//Static member variables must be initialized. Unless you're using C++11, or it's an integer type,
//they have to be defined and initialized outside of the class like this:
MyClass::myStaticVar = 0;
MyClass classA;
MyClass classB;
Каждый экземпляр MyClass имеет свой собственный myVar, но имеет один и тот же myStaticVar. На самом деле вам даже не нужен экземпляр MyClass для доступа к myStaticVar, и вы можете получить к нему доступ вне класса следующим образом:
MyClass::myStaticVar //Assuming it's publicly accessible.
При использовании внутри функции в качестве локальной переменной (а не в качестве переменной-члена класса) ключевое слово static делает что-то другое. Это позволяет вам создавать постоянные переменные, не давая глобальной области видимости.
int myFunc()
{
int myVar = 0; //Each time the code reaches here, a new variable called 'myVar' is initialized.
myVar++;
//Given the above code, this will *always* print '1'.
std::cout << myVar << std::endl;
//The first time the code reaches here, 'myStaticVar' is initialized. But ONLY the first time.
static int myStaticVar = 0;
//Each time the code reaches here, myStaticVar is incremented.
myStaticVar++;
//This will print a continuously incrementing number,
//each time the function is called. '1', '2', '3', etc...
std::cout << myStaticVar << std::endl;
}
Это глобальная переменная с точки зрения постоянства... но не глобальная по объему / доступности.
Вы также можете иметь статические функции-члены. Статические функции в основном не являются членами, но находятся внутри пространства имен имени класса и имеют частный доступ к членам класса.
class MyClass
{
public:
int Func()
{
//...do something...
}
static int StaticFunc()
{
//...do something...
}
};
int main()
{
MyClass myClassA;
myClassA.Func(); //Calls 'Func'.
myClassA.StaticFunc(); //Calls 'StaticFunc'.
MyClass::StaticFunc(); //Calls 'StaticFunc'.
MyClass::Func(); //Error: You can't call a non-static member-function without a class instance!
return 0;
}
Когда вы вызываете функцию-член, появляется скрытый параметр с именем 'this', который является указателем на экземпляр класса, вызывающего функцию. Статические функции-члены не имеют этого скрытого параметра... они могут вызываться без экземпляра класса, но также не могут получить доступ к нестатическим переменным-членам класса, потому что у них нет указателя this для работы. Они не вызываются ни для какого конкретного экземпляра класса.
Я не программист на C, поэтому я не могу дать вам информацию об использовании static в программе на C должным образом, но когда дело доходит до объектно-ориентированного программирования, static в основном объявляет переменную или функцию или класс одинаковыми. на протяжении всей жизни программы. Взять к примеру.
class A
{
public:
A();
~A();
void somePublicMethod();
private:
void somePrivateMethod();
};
Когда вы создаете этот класс в своем Main, вы делаете что-то вроде этого.
int main()
{
A a1;
//do something on a1
A a2;
//do something on a2
}
Эти два экземпляра класса полностью отличаются друг от друга и работают независимо друг от друга. Но если бы вы воссоздали класс А вот так.
class A
{
public:
A();
~A();
void somePublicMethod();
static int x;
private:
void somePrivateMethod();
};
Вернемся к основному снова.
int main()
{
A a1;
a1.x = 1;
//do something on a1
A a2;
a2.x++;
//do something on a2
}
Тогда a1 и a2 будут совместно использовать одну и ту же копию int x, в результате чего любые операции над x в a1 будут напрямую влиять на операции x в a2. Так что, если бы я должен был сделать это
int main()
{
A a1;
a1.x = 1;
//do something on a1
cout << a1.x << endl; //this would be 1
A a2;
a2.x++;
cout << a2.x << endl; //this would be 2
//do something on a2
}
Оба экземпляра класса A имеют общие статические переменные и функции. Надеюсь, что это ответ на ваш вопрос. Мои ограниченные знания C позволяют мне сказать, что определение функции или переменной как статической означает, что для файла видно, что функция или переменная определяется как статическая. Но на этот вопрос лучше бы ответил парень из C, а не я. C++ позволяет как C, так и C++ объявлять ваши переменные как статические, потому что они полностью обратно совместимы с C.
Статический объект: мы можем определить статические члены класса, используя ключевое слово static. Когда мы объявляем член класса статическим, это означает, что независимо от того, сколько объектов класса создано, существует только одна копия статического члена.
Статический член является общим для всех объектов класса. Все статические данные инициализируются нулем при создании первого объекта, если нет других инициализаций. Мы не можем поместить его в определение класса, но его можно инициализировать вне класса, как это сделано в следующем примере, путем повторного выделения статической переменной с использованием оператора разрешения области:: для определения, к какому классу он принадлежит.
Давайте попробуем следующий пример, чтобы понять концепцию статических членов данных:
#include <iostream>
using namespace std;
class Box
{
public:
static int objectCount;
// Constructor definition
Box(double l=2.0, double b=2.0, double h=2.0)
{
cout <<"Constructor called." << endl;
length = l;
breadth = b;
height = h;
// Increase every time object is created
objectCount++;
}
double Volume()
{
return length * breadth * height;
}
private:
double length; // Length of a box
double breadth; // Breadth of a box
double height; // Height of a box
};
// Initialize static member of class Box
int Box::objectCount = 0;
int main(void)
{
Box Box1(3.3, 1.2, 1.5); // Declare box1
Box Box2(8.5, 6.0, 2.0); // Declare box2
// Print total number of objects.
cout << "Total objects: " << Box::objectCount << endl;
return 0;
}
Когда приведенный выше код компилируется и выполняется, он дает следующий результат:
Constructor called.
Constructor called.
Total objects: 2
Статические члены-функции. Объявляя член функции как статический, вы делаете его независимым от какого-либо конкретного объекта класса. Статическая функция-член может быть вызвана, даже если объекты класса не существуют, и к статическим функциям можно обращаться, используя только имя класса и оператор разрешения области::.
Статическая функция-член может получить доступ только к статическим данным-членам, другим статическим функциям-членам и любым другим функциям вне класса.
Статические функции-члены имеют область видимости класса и не имеют доступа к указателю this класса. Вы можете использовать статическую функцию-член, чтобы определить, были ли созданы некоторые объекты класса или нет.
Давайте попробуем следующий пример, чтобы понять концепцию статических членов функции:
#include <iostream>
using namespace std;
class Box
{
public:
static int objectCount;
// Constructor definition
Box(double l=2.0, double b=2.0, double h=2.0)
{
cout <<"Constructor called." << endl;
length = l;
breadth = b;
height = h;
// Increase every time object is created
objectCount++;
}
double Volume()
{
return length * breadth * height;
}
static int getCount()
{
return objectCount;
}
private:
double length; // Length of a box
double breadth; // Breadth of a box
double height; // Height of a box
};
// Initialize static member of class Box
int Box::objectCount = 0;
int main(void)
{
// Print total number of objects before creating object.
cout << "Inital Stage Count: " << Box::getCount() << endl;
Box Box1(3.3, 1.2, 1.5); // Declare box1
Box Box2(8.5, 6.0, 2.0); // Declare box2
// Print total number of objects after creating object.
cout << "Final Stage Count: " << Box::getCount() << endl;
return 0;
}
Когда приведенный выше код компилируется и выполняется, он дает следующий результат:
Inital Stage Count: 0
Constructor called.
Constructor called.
Final Stage Count: 2
Что это значит с локальной переменной? Это локальная переменная функции?
Да - Неглобальный, такой как локальная переменная функции.
Потому что есть также то, что когда вы объявляете функцию local как статическую, она инициализируется только один раз, когда она впервые входит в эту функцию.
Правильно.
Он также говорит только о продолжительности хранения в отношении членов класса, а как насчет того, чтобы он не был специфичным для экземпляра, это также свойство static no? Или это продолжительность хранения?
class R { static int a; }; // << static lives for the duration of the program
то есть все случаи R
доля int R::a
- int R::a
никогда не копируется
А как насчет случая со статической и файловой областью?
Эффективно глобальный, который имеет конструктор / деструктор, где это уместно - инициализация не откладывается до доступа.
Как статические связаны со связью переменной?
Для функции local она является внешней. Доступ: он доступен для функции (если, конечно, вы ее не вернете).
Для класса это внешнее. Доступ: применяются стандартные спецификаторы доступа (открытый, защищенный, частный).
static
также можно указать внутреннюю связь, в зависимости от того, где она объявлена (файл / пространство имен).
Это целое статическое ключевое слово совершенно сбивает с толку
У него слишком много целей в C++.
Может кто-нибудь прояснить различные варианты использования английского языка, а также сказать мне, когда инициализировать статический член класса?
Это автоматически инициализируется перед main
если он загружен и имеет конструктор. Это может звучать как хорошая вещь, но порядок инициализации в значительной степени находится вне вашего контроля, поэтому сложную инициализацию становится очень трудно поддерживать, и вы хотите минимизировать это - если у вас есть статический тип, то функция локального масштабирования гораздо лучше масштабируется по библиотекам и проекты. Что касается данных со статической продолжительностью хранения, вы должны попытаться минимизировать этот дизайн, особенно если он изменчив (глобальные переменные). "Время" инициализации также варьируется по ряду причин - у загрузчика и ядра есть некоторые приемы, позволяющие минимизировать использование памяти и отложить инициализацию, в зависимости от данных.