Ir para o conteúdo

Última atualização:2026-10-13

static em C++: variáveis e membros estáticos

Sobre o autor

Conta pública no WeChat:

static em C++ explicado: variáveis, membros e funções estáticas | C++那些事

Quando usada com diferentes tipos de entidades, a palavra-chave static tem significados diferentes. Podemos usar a palavra-chave static:

Variáveis estáticas: variáveis em uma função, variáveis em uma classe

Membros estáticos da classe: objetos da classe e funções em uma classe

Agora vamos ver em detalhe esses usos de static:

Variáveis estáticas

  • Variáveis estáticas em uma função

Quando uma variável é declarada static, o espaço é alocado pelo tempo de vida do programa. Mesmo que a função seja chamada várias vezes, o espaço da variável estática é alocado apenas uma vez, e o valor da variável da chamada anterior é levado para a próxima chamada da função. Isso é muito útil em C / C++ ou em qualquer outra aplicação que precise armazenar o estado anterior de uma função.

#include <iostream> 
#include <string> 
using namespace std; 

void demo() 
{ 
    // static variable 
    static int count = 0; 
    cout << count << " "; 

    // value is updated and 
    // will be carried to next 
    // function calls 
    count++; 
} 

int main() 
{ 
    for (int i=0; i<5; i++)  
        demo(); 
    return 0; 
} 

Saída:

0 1 2 3 4 

Você pode ver no programa acima que a variável count foi declarada static. Portanto, o seu valor é levado através das chamadas da função. A cada chamada da função, a variável count não é inicializada novamente.

  • Variáveis estáticas em uma classe

Como as variáveis declaradas static são inicializadas apenas uma vez — pois têm espaço alocado em um armazenamento estático separado —, as variáveis estáticas de uma classe são compartilhadas pelos objetos. Não pode haver várias cópias da mesma variável estática para objetos diferentes. É também por esse motivo que variáveis estáticas não podem ser inicializadas usando um construtor.

#include<iostream> 
using namespace std; 

class Apple 
{ 
public: 
    static int i; 

    Apple() 
    { 
        // Do nothing 
    }; 
}; 

int main() 
{ 
Apple obj1; 
Apple obj2; 
obj1.i =2; 
obj2.i = 3; 

// prints value of i 
cout << obj1.i<<" "<<obj2.i; 
} 

Você pode ver no programa acima que tentamos criar várias cópias da variável estática i para vários objetos. Mas isso não aconteceu. Portanto, uma variável estática em uma classe deve ser explicitamente inicializada pelo usuário fora da classe, usando o nome da classe e o operador de resolução de escopo, como mostrado a seguir:

#include<iostream> 
using namespace std; 

class Apple 
{ 
public: 
    static int i; 

    Apple() 
    { 
        // Do nothing 
    }; 
}; 

int Apple::i = 1; 

int main() 
{ 
    Apple obj; 
    // prints value of i 
    cout << obj.i; 
} 

Saída:

1

Membros estáticos

  • Objetos de classe como estáticos

Assim como as variáveis, os objetos declarados static também têm escopo até o fim do tempo de vida do programa.

Considere o programa a seguir, no qual o objeto não é estático.

#include<iostream> 
using namespace std; 

class Apple 
{ 
    int i; 
    public: 
        Apple() 
        { 
            i = 0; 
            cout << "Inside Constructor\n"; 
        } 
        ~Apple() 
        { 
            cout << "Inside Destructor\n"; 
        } 
}; 

int main() 
{ 
    int x = 0; 
    if (x==0) 
    { 
        Apple obj; 
    } 
    cout << "End of main\n"; 
} 

Saída:

Inside Constructor
Inside Destructor
End of main

No programa acima, o objeto é declarado não estático dentro do bloco if. Portanto, o escopo da variável é apenas dentro do bloco if. Assim, quando o objeto é criado, o construtor é chamado, e o destruidor é chamado no momento em que o controle do bloco if o ultrapassa, porque o escopo do objeto se limita ao bloco if em que foi declarado.

Se declararmos o objeto como estático, vejamos agora como a saída muda.

#include<iostream> 
using namespace std; 

class Apple 
{ 
    int i; 
    public: 
        Apple() 
        { 
            i = 0; 
            cout << "Inside Constructor\n"; 
        } 
        ~Apple() 
        { 
            cout << "Inside Destructor\n"; 
        } 
}; 

int main() 
{ 
    int x = 0; 
    if (x==0) 
    { 
        static Apple obj; 
    } 
    cout << "End of main\n"; 
} 

Saída:

Inside Constructor
End of main
Inside Destructor

Você pode ver claramente a mudança na saída. Agora o destruidor é chamado depois do fim de main. Isso ocorre porque o escopo de um objeto estático se estende por todo o tempo de vida do programa.

  • Funções estáticas em uma classe

Assim como os membros de dados estáticos ou as variáveis estáticas de uma classe, as funções-membro estáticas também não dependem dos objetos da classe. Somos autorizados a chamar uma função-membro estática usando um objeto e '.'. No entanto, recomenda-se chamar membros estáticos usando o nome da classe e o operador de resolução de escopo.

As funções-membro estáticas só têm permissão para acessar membros de dados estáticos ou outras funções-membro estáticas; elas não conseguem acessar os membros de dados não estáticos nem as funções-membro da classe.

#include<iostream> 
using namespace std; 

class Apple 
{ 
    public: 
        // static member function 
        static void printMsg() 
        {
            cout<<"Welcome to Apple!"; 
        }
}; 

// main function 
int main() 
{ 
    // invoking a static member function 
    Apple::printMsg(); 
} 

Saída:

Welcome to Apple!

Restrição do escopo de acesso

static também tem a função de restringir o escopo de acesso (de modo semelhante a um namespace anônimo). Da issue: https://github.com/Light-City/CPlusPlusThings/issues/142

// source1.cpp
extern void sayHello();
const char* msg = "Hello World!\n";
int main()
{
    sayHello();
    return 0;
}

// source2.cpp
#include <cstdio>
extern char* msg;
void sayHello()
{
    printf("%s", msg);
}

O g++ compila normalmente os dois arquivos de código acima e imprime Hello World!, mas se você adicionar static a msg em source1.cpp, isso causa um erro de compilação 'undefined reference to msg':

// source1.cpp
extern void sayHello();
static const char* msg = "Hello World!\n";
int main()
{
    sayHello();
    return 0;
}

Ligação interna de static (restrição do escopo de acesso)

Agradecemos à issue #142 pela observação: quando static qualifica uma variável/função global, ele também cumpre o papel de restringir o escopo de acesso — muda a sua ligação (linkage) de externa para interna, com um efeito semelhante ao de um namespace anônimo:

  • Variável global sem static: outras unidades de tradução podem acessá-la por meio de uma declaração extern;
  • Variável/função global static: visível apenas na unidade de tradução atual; nem mesmo uma declaração extern consegue ligar-se a ela (undefined reference).

No C++ moderno é mais recomendado usar um namespace anônimo para expressar "visível apenas neste arquivo" (também funciona para tipos), mas entender essa faceta do static é muito importante ao ler código antigo.

// file1.cpp
static int hidden = 42;          // 内部链接:其他文件 extern 不可见
int visible = 1;                 // 外部链接:其他文件可 extern 访问

namespace {                      // 匿名命名空间:等价且更现代的写法
    int also_hidden = 7;
}

Perguntas frequentes

Como uma global static difere de uma global normal?

A global static tem ligação interna: visível apenas na sua unidade de tradução. A global normal é visível entre arquivos e propensa a conflitos de símbolos.

Quando uma variável local static é inicializada?

Uma vez, na primeira passagem pela definição; desde C++11 de forma thread-safe, e vive até o fim do programa.

Uma função-membro static pode acessar membros não estáticos?

Não. Ela não tem ponteiro this, então só acessa membros estáticos.

Tópicos relacionados

Comentários