Para aclarar la pregunta, preferiría clasificar el uso de la palabra clave 'estática' en tres formas diferentes:
(UNA). variables
(SI). funciones
(C). variables miembro / funciones de clases
la explicación sigue a continuación para cada uno de los subtítulos:
(A) palabra clave 'estática' para variables
Este puede ser un poco complicado, sin embargo, si se explica y comprende correctamente, es bastante sencillo.
Para explicar esto, primero es realmente útil saber sobre el alcance, la duración y la vinculación de las variables, sin las cuales las cosas siempre son difíciles de ver a través del concepto turbio de palabra clave estática
1. Alcance : determina dónde está accesible la variable en el archivo. Puede ser de dos tipos: (i) Alcance local o de bloque . (ii) Alcance global
2. Duración : determina cuándo se crea y destruye una variable. De nuevo, es de dos tipos: (i) Duración automática de almacenamiento (para variables que tienen alcance local o de bloque). (ii) Duración del almacenamiento estático (para variables que tienen alcance global o variables locales (en una función o en un bloque de código) con especificador estático ).
3. Vinculación : determina si se puede acceder (o vincular) a una variable en otro archivo. Nuevamente (y afortunadamente) es de dos tipos: (i) Enlace interno
(para variables que tienen alcance de bloque y alcance global / alcance de archivo / alcance de espacio de nombres global) (ii) enlace externo (para variables que tienen solo alcance global / alcance de archivo / Alcance del espacio de nombres global)
Veamos un ejemplo a continuación para comprender mejor las variables globales y locales simples (no hay variables locales con duración de almacenamiento estático):
//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
Ahora viene el concepto de vinculación. Cuando una variable global definida en un archivo está destinada a ser utilizada en otro archivo, el enlace de la variable juega un papel importante.
El enlace de variables globales se especifica mediante las palabras clave: (i) estático y (ii) externo
(Ahora obtienes la explicación)
La palabra clave estática se puede aplicar a variables con alcance local y global, y en ambos casos, significan cosas diferentes. Primero explicaré el uso de la palabra clave 'estática' en variables con alcance global (donde también aclararé el uso de la palabra clave 'extern') y más tarde para aquellos con alcance local.
1. Palabra clave estática para variables con alcance global
Las variables globales tienen una duración estática, lo que significa que no quedan fuera del alcance cuando finaliza un bloque de código particular (por ejemplo, main ()) en el que se usa. Dependiendo de la vinculación, se puede acceder a ellos solo dentro del mismo archivo donde se declaran (para la variable global estática) o fuera del archivo, incluso fuera del archivo en el que se declaran (variables globales de tipo externo)
En el caso de una variable global que tenga un especificador externo, y si se accede a esta variable fuera del archivo en el que se ha inicializado, debe declararse hacia adelante en el archivo donde se está utilizando, al igual que una función debe ser hacia adelante declarado si su definición está en un archivo diferente de donde se está utilizando.
Por el contrario, si la variable global tiene una palabra clave estática, no se puede usar en un archivo fuera del cual se ha declarado.
(ver ejemplo a continuación para aclaraciones)
p.ej:
//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;
}
ahora cualquier variable en c ++ puede ser const o no const y para cada 'const-ness' obtenemos dos casos de enlace por defecto de c ++, en caso de que no se especifique ninguno:
(i) Si una variable global no es constante, su vinculación es externa por defecto , es decir, se puede acceder a la variable global no constante en otro archivo .cpp mediante declaración directa utilizando la palabra clave externa (en otras palabras, no global constante las variables tienen enlace externo (con duración estática, por supuesto)). Además, el uso de palabras clave externas en el archivo original donde se ha definido es redundante. En este caso, para hacer que una variable global no constante sea inaccesible a un archivo externo, use el especificador 'estático' antes del tipo de la variable .
(ii) Si una variable global es constante, su vinculación es estática por defecto , es decir, no se puede acceder a una variable global constante en un archivo que no sea donde se define (en otras palabras, las variables globales constantes tienen vinculación interna (con duración estática) por supuesto)). También es redundante el uso de palabras clave estáticas para evitar el acceso a una variable global constante en otro archivo. Aquí, para hacer que una variable global constante tenga un enlace externo, use el especificador 'extern' antes del tipo de la variable
Aquí hay un resumen de las variables de alcance global con varios enlaces.
//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
A continuación, investigamos cómo se comportan las variables globales anteriores cuando se accede a ellas en un archivo diferente.
//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. Palabra clave estática para variables con alcance local
Actualizaciones (agosto de 2019) sobre palabras clave estáticas para variables en ámbito local
Esto se puede subdividir en dos categorías:
(i) palabra clave estática para variables dentro de un bloque de funciones , y (ii) palabra clave estática para variables dentro de un bloque local sin nombre.
(i) palabra clave estática para variables dentro de un bloque de funciones.
Anteriormente, mencioné que las variables con alcance local tienen una duración automática, es decir, llegan a existir cuando se ingresa el bloque (ya sea un bloque normal, sea un bloque de función) y dejan de existir cuando el bloque termina, en pocas palabras, variables con alcance local tienen duración automática y las variables de duración automática (y los objetos) no tienen vinculación, lo que significa que no son visibles fuera del bloque de código.
Si el especificador estático se aplica a una variable local dentro de un bloque de funciones, cambia la duración de la variable de automática a estática y su tiempo de vida es la duración completa del programa, lo que significa que tiene una ubicación de memoria fija y su valor solo se inicializa una vez antes del inicio del programa como se menciona en la referencia de cpp (la inicialización no debe confundirse con la asignación)
Veamos un ejemplo.
//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;
}
Al observar el criterio anterior para las variables locales estáticas y las variables globales estáticas, uno podría verse tentado a preguntar cuál podría ser la diferencia entre ellas. Mientras que las variables globales son accesibles en cualquier punto dentro del código (en la misma unidad de traducción, así como en diferentes unidades, dependiendo de la const -ness y extern -ness), una variable estática definida dentro de un bloque de funciones no es directamente accesible. La variable tiene que ser devuelta por el valor de la función o referencia. Vamos a demostrar esto con un ejemplo:
//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;
}
Se puede encontrar más explicaciones sobre la elección de la variable estática global y local estática en este hilo de stackoverflow
(ii) palabra clave estática para variables dentro de un bloque local sin nombre.
No se puede acceder a las variables estáticas dentro de un bloque local (no un bloque de función) fuera del bloque una vez que el bloque local queda fuera de alcance. No hay advertencias a esta regla.
//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 introdujo la palabra clave constexpr
que garantiza la evaluación de una expresión en tiempo de compilación y permite al compilador optimizar el código. Ahora, si el valor de una variable constante estática dentro de un ámbito se conoce en tiempo de compilación, el código se optimiza de una manera similar a la que tiene constexpr
. Aquí hay un pequeño ejemplo
Recomiendo a los lectores que también busquen la diferencia entre constexpr
y static const
para las variables en este hilo de stackoverflow . Esto concluye mi explicación de la palabra clave estática aplicada a las variables.
B. palabra clave 'estática' utilizada para funciones
En términos de funciones, la palabra clave estática tiene un significado directo. Aquí, se refiere al enlace de la función
Normalmente, todas las funciones declaradas dentro de un archivo cpp tienen enlace externo por defecto, es decir, una función definida en un archivo puede usarse en otro archivo cpp mediante declaración directa.
el uso de una palabra clave estática antes de que la declaración de función limite su vinculación a interna , es decir, una función estática no se puede usar dentro de un archivo fuera de su definición.
C. Palabra clave Staitc utilizada para variables miembro y funciones de clases
1. palabra clave 'estática' para variables miembro de clases
Empiezo directamente con un ejemplo aquí
#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;
}
En este ejemplo, la variable estática m_designNum conserva su valor y esta variable de miembro privado único (porque es estática) se comparte en blanco y negro con todas las variables del tipo de objeto DesignNumber
Además, como otras variables miembro, las variables miembro estáticas de una clase no están asociadas con ningún objeto de clase, lo que se demuestra al imprimir anyNumber en la función principal
variables miembro estáticas const vs no const en clase
(i) variables de miembro estático de clase no constante
En el ejemplo anterior, los miembros estáticos (públicos y privados) no eran constantes. El estándar ISO prohíbe que los miembros estáticos no constantes se inicialicen en la clase. Por lo tanto, como en el ejemplo anterior, deben inicializarse después de la definición de clase, con la advertencia de que la palabra clave estática debe omitirse
(ii) variables miembro const-static de clase
esto es sencillo y va con la convención de la inicialización de otras variables miembro const, es decir, las variables miembro const static de una clase se pueden inicializar en el punto de declaración y se pueden inicializar al final de la declaración de clase con una advertencia de que la palabra clave const debe agregarse al miembro estático cuando se inicializa después de la definición de clase.
Sin embargo, recomendaría inicializar las variables miembro estáticas constantes en el punto de declaración. Esto va con la convención estándar de C ++ y hace que el código se vea más limpio
Para obtener más ejemplos sobre variables miembro estáticas en una clase, busque el siguiente enlace en learncpp.com
http://www.learncpp.com/cpp-tutorial/811-static-member-variables/
2. palabra clave 'estática' para la función miembro de clases
Al igual que las variables miembro de las clases pueden ser estáticas, también pueden las funciones miembro de las clases. Las funciones miembro normales de las clases siempre están asociadas con un objeto del tipo de clase. Por el contrario, las funciones miembro estáticas de una clase no están asociadas con ningún objeto de la clase, es decir, no tienen * este puntero.
En segundo lugar, dado que las funciones miembro estáticas de la clase no tienen * este puntero, pueden llamarse utilizando el operador de resolución de alcance y nombre de clase en la función principal (ClassName :: functionName ();)
En tercer lugar, las funciones miembro estáticas de una clase solo pueden acceder a las variables miembro estáticas de una clase, ya que las variables miembro no estáticas de una clase deben pertenecer a un objeto de clase.
Para obtener más ejemplos sobre funciones miembro estáticas en una clase, consulte el siguiente enlace de learncpp.com
http://www.learncpp.com/cpp-tutorial/812-static-member-functions/