Para esclarecer a questão, prefiro categorizar o uso da palavra-chave 'estática' de três formas diferentes:
(UMA). variáveis
(B) funções
(C) variáveis-membro / funções de classes
a explicação a seguir para cada um dos subtítulos:
(A) palavra-chave 'estática' para variáveis
Este pode ser um pouco complicado, no entanto, se explicado e entendido corretamente, é bem direto.
Para explicar isso, primeiro é realmente útil saber sobre o escopo, a duração e a ligação das variáveis, sem as quais as coisas sempre são difíceis de ver através do conceito obscuro da palavra-chave staic
1. Escopo : determina onde, no arquivo, a variável está acessível. Pode ser de dois tipos: (i) Local ou Escopo do Bloco . (ii) Escopo Global
2. Duração : determina quando uma variável é criada e destruída. Novamente, é de dois tipos: (i) Duração automática do armazenamento (para variáveis com escopo Local ou Bloco). (ii) Duração de armazenamento estático (para variáveis com escopo global ou variáveis locais (em uma função ou a em um bloco de código) com especificador estático ).
3. Vinculação : determina se uma variável pode ser acessada (ou vinculada) em outro arquivo. Novamente (e felizmente), ele é de dois tipos: (i) Ligação interna
(para variáveis com escopo de bloco e Escopo global / Escopo de arquivo / Escopo de espaço para nome global) (ii) Ligação externa (para variáveis com apenas escopo global / Escopo de arquivo / Escopo do Namespace Global)
Vamos consultar um exemplo abaixo para entender melhor as variáveis globais e locais simples (sem variáveis locais com duração de armazenamento 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
Agora vem o conceito de ligação. Quando uma variável global definida em um arquivo se destina a ser usada em outro arquivo, a ligação da variável desempenha um papel importante.
A ligação de variáveis globais é especificada pelas palavras-chave: (i) estática e (ii) externa
(Agora você obtém a explicação)
A palavra-chave estática pode ser aplicada a variáveis com escopo local e global e, nos dois casos, elas significam coisas diferentes. Primeiro, explicarei o uso da palavra-chave 'estática' em variáveis com escopo global (onde também esclareço o uso da palavra-chave 'extern') e, posteriormente, para aquelas com escopo local.
1. Palavra-chave estática para variáveis com escopo global
Variáveis globais têm duração estática, o que significa que não ficam fora do escopo quando um bloco de código específico (por exemplo, main ()) no qual é usado termina. Dependendo da ligação, eles podem ser acessados apenas dentro do mesmo arquivo em que são declarados (para variável global estática) ou fora do arquivo, mesmo fora do arquivo em que foram declarados (variáveis globais do tipo externo)
No caso de uma variável global com especificador externo, e se essa variável estiver sendo acessada fora do arquivo em que foi inicializada, ela deve ser declarada para frente no arquivo em que está sendo usada, assim como uma função deve ser encaminhada declarado se sua definição estiver em um arquivo diferente de onde está sendo usado.
Por outro lado, se a variável global tiver uma palavra-chave estática, ela não poderá ser usada em um arquivo fora do qual foi declarada.
(veja o exemplo abaixo para esclarecimentos)
por exemplo:
//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;
}
agora qualquer variável em c ++ pode ser uma const ou uma não-const e, para cada 'constância', obtemos dois casos de ligação c ++ padrão, caso nenhuma seja especificada:
(i) Se uma variável global não for const, seu vínculo é externo por padrão , ou seja, a variável global não const pode ser acessada em outro arquivo .cpp por declaração direta usando a palavra-chave extern (em outras palavras, non const global variáveis têm ligação externa (com duração estática, é claro)). Também o uso da palavra-chave externa no arquivo original em que foi definida é redundante. Nesse caso, para tornar uma variável global não const inacessível ao arquivo externo, use o especificador 'estático' antes do tipo da variável .
(ii) Se uma variável global é const, seu vínculo é estático por padrão , ou seja, uma variável global const não pode ser acessada em um arquivo que não seja o local onde está definido (em outras palavras, variáveis globais const têm vínculo interno (com duração estática claro)). Também o uso da palavra-chave estática para impedir que uma variável global const seja acessada em outro arquivo é redundante. Aqui, para fazer uma variável global const ter uma ligação externa, use o especificador 'extern' antes do tipo da variável
Aqui está um resumo para variáveis de escopo global com várias ligações
//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 seguir, investigamos como as variáveis globais acima se comportam quando acessadas em um arquivo 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. Palavra-chave estática para variáveis com escopo local
Atualizações (agosto de 2019) na palavra-chave estática para variáveis no escopo local
Isso ainda pode ser subdividido em duas categorias:
(i) palavra-chave estática para variáveis dentro de um bloco de função e (ii) palavra-chave estática para variáveis dentro de um bloco local sem nome.
(i) palavra-chave estática para variáveis dentro de um bloco de funções.
Mencionei anteriormente que variáveis com escopo local têm duração automática, ou seja, passam a existir quando o bloco é inserido (seja um bloco normal, seja um bloco funcional) e deixam de existir quando o bloco termina, para resumir a história, variáveis com escopo local têm duração automática e variáveis de duração automática (e objetos) não têm vínculo, o que significa que não são visíveis fora do bloco de código.
Se o especificador estático for aplicado a uma variável local dentro de um bloco de função, ele altera a duração da variável de automática para estática e seu tempo de vida é toda a duração do programa, o que significa que ele possui um local de memória fixo e seu valor é inicializado apenas uma vez antes da inicialização do programa, conforme mencionado na referência cpp (a inicialização não deve ser confundida com a atribuição)
vamos dar uma olhada em um exemplo.
//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;
}
Observando o critério acima para variáveis locais estáticas e variáveis globais estáticas, pode-se tentar perguntar qual a diferença entre elas. Enquanto as variáveis globais estão acessíveis em qualquer ponto dentro do código (na mesma, bem como unidade de conversão diferente dependendo da const -ness e externo -ness), uma variável estático definido dentro de um bloco de função não é directamente acessível. A variável deve ser retornada pelo valor ou referência da função. Vamos demonstrar isso por um exemplo:
//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;
}
Mais explicações sobre a escolha da variável estática global e local estática podem ser encontradas neste encadeamento stackoverflow
(ii) palavra-chave estática para variáveis dentro de um bloco local sem nome.
variáveis estáticas dentro de um bloco local (não um bloco funcional) não podem ser acessadas fora do bloco depois que o bloco local fica fora do escopo. Sem ressalvas a esta regra.
//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;
}
O C ++ 11 introduziu a palavra-chave constexpr
que garante a avaliação de uma expressão em tempo de compilação e permite que o compilador otimize o código. Agora, se o valor de uma variável const estática dentro de um escopo for conhecido em tempo de compilação, o código será otimizado de maneira semelhante à que existe constexpr
. Aqui está um pequeno exemplo
Eu recomendo que os leitores também procurem a diferença entre constexpr
e static const
para variáveis neste encadeamento de fluxo de pilha . isso conclui minha explicação para a palavra-chave estática aplicada às variáveis.
B. Palavra-chave 'estática' usada para funções
em termos de funções, a palavra-chave estática tem um significado direto. Aqui, refere - se ao vínculo da função
Normalmente, todas as funções declaradas em um arquivo cpp têm vínculo externo por padrão, ou seja, uma função definida em um arquivo pode ser usada em outro arquivo cpp por declaração direta.
usando uma palavra-chave estática antes da declaração da função limitar sua ligação a interna , ou seja, uma função estática não pode ser usada dentro de um arquivo fora de sua definição.
C. Staitc Palavra-chave usada para variáveis-membro e funções de classes
1. palavra-chave 'estática' para variáveis-membro de classes
Eu começo diretamente com um exemplo aqui
#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;
}
Neste exemplo, a variável estática m_designNum mantém seu valor e essa variável de membro particular privada (por ser estática) é compartilhada entre todas as variáveis do tipo de objeto DesignNumber
Também como outras variáveis de membro, as variáveis de membro estáticas de uma classe não estão associadas a nenhum objeto de classe, o que é demonstrado pela impressão de anyNumber na função principal
variáveis de membro estático const vs não-const na classe
(i) variáveis de membro estático da classe não const
No exemplo anterior, os membros estáticos (públicos e privados) eram não constantes. O padrão ISO proíbe que os membros estáticos não-constantes sejam inicializados na classe. Portanto, como no exemplo anterior, eles devem ser inicializados após a definição da classe, com a ressalva de que a palavra-chave estática precisa ser omitida
(ii) variáveis de membro const-static da classe
isso é simples e segue a convenção de outra inicialização de variável de membro const, ou seja, as variáveis de membro const static de uma classe podem ser inicializadas no ponto da declaração e no final da declaração da declaração de classe com uma ressalva de que a palavra-chave const precisa ser adicionada ao membro estático ao ser inicializada após a definição da classe.
No entanto, eu recomendaria inicializar as variáveis de membro estático const no ponto de declaração. Isso acompanha a convenção C ++ padrão e torna o código mais limpo
Para obter mais exemplos sobre variáveis estáticas de membros em uma classe, consulte o seguinte link em learncpp.com
http://www.learncpp.com/cpp-tutorial/811-static-member-variables/
2. Palavra-chave 'estática' para função de membro de classes
Assim como variáveis de membro de classes podem, ser estáticas, também podem funções de membro de classes. As funções de membro normais das classes são sempre associadas a um objeto do tipo de classe. Por outro lado, funções de membro estáticas de uma classe não estão associadas a nenhum objeto da classe, ou seja, elas não possuem esse ponteiro.
Em segundo lugar, como as funções de membro estático da classe não possuem esse ponteiro, elas podem ser chamadas usando o nome da classe e o operador de resolução do escopo na função principal (ClassName :: functionName ();)
Terceiro, as funções de membro estático de uma classe só podem acessar variáveis de membro estático de uma classe, pois as variáveis de membro não estático de uma classe devem pertencer a um objeto de classe.
Para obter mais exemplos de funções membro estáticas em uma classe, consulte o seguinte link em learncpp.com
http://www.learncpp.com/cpp-tutorial/812-static-member-functions/