Saltar a contenido

Última actualización:2026-10-13

static en C++: variables y miembros estáticos

Sobre el autor

Cuenta pública de WeChat:

static en C++ explicado: variables, miembros y funciones estáticas | C++那些事

Cuando se usa junto a distintos tipos de entidades, la palabra clave static tiene significados diferentes. Podemos usar la palabra clave static:

Variables estáticas: variables en una función, variables en una clase

Miembros estáticos de una clase: objetos de la clase y funciones en una clase

Ahora veamos en detalle estos usos de static:

Variables estáticas

  • Variables estáticas en una función

Cuando una variable se declara static, el espacio se asigna durante todo el tiempo de vida del programa. Aunque se llame a la función muchas veces, el espacio de la variable estática se asigna solo una vez, y el valor de la variable de la llamada anterior se transmite a la siguiente llamada de la función. Esto resulta muy útil en C / C++ o en cualquier otra aplicación que necesite almacenar el estado anterior de una función.

#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; 
} 

Salida:

0 1 2 3 4 

Puedes ver en el programa anterior que la variable count se declara static. Por eso su valor se transmite de una llamada a otra de la función. Cada vez que se llama a la función, no se inicializa de nuevo la variable count.

  • Variables estáticas en una clase

Como las variables declaradas static se inicializan una sola vez —ya que se les asigna espacio en un almacenamiento estático separado—, las variables estáticas de una clase se comparten entre los objetos. No puede haber varias copias de la misma variable estática para objetos distintos. Precisamente por esta razón, las variables estáticas no pueden inicializarse mediante un constructor.

#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; 
} 

Puedes ver en el programa anterior que hemos intentado crear varias copias de la variable estática i para varios objetos. Pero eso no ocurrió. Por tanto, una variable estática de una clase debe inicializarse explícitamente el usuario fuera de la clase, usando el nombre de la clase y el operador de resolución de ámbito, tal como se muestra a continuación:

#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; 
} 

Salida:

1

Miembros estáticos

  • Objetos de clase como estáticos

Al igual que las variables, los objetos declarados static también tienen un ámbito que dura hasta el final del tiempo de vida del programa.

Considera el siguiente programa, en el que el objeto no es 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"; 
} 

Salida:

Inside Constructor
Inside Destructor
End of main

En el programa anterior, el objeto se declara no estático dentro del bloque if. Por lo tanto, el ámbito de la variable queda limitado al bloque if. Así, al crearse el objeto se llama al constructor, y el destructor se invoca en el momento en que el control del bloque if lo sobrepasa, porque el ámbito del objeto está limitado al bloque if donde se declaró.

Si declaramos el objeto como estático, veamos ahora cómo cambia la salida.

#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"; 
} 

Salida:

Inside Constructor
End of main
Inside Destructor

Puedes ver claramente el cambio en la salida. Ahora el destructor se llama después del final de main. Esto se debe a que el ámbito de un objeto estático abarca todo el tiempo de vida del programa.

  • Funciones estáticas en una clase

Al igual que los miembros de datos estáticos o las variables estáticas de una clase, las funciones miembro estáticas tampoco dependen de los objetos de la clase. Se nos permite invocar una función miembro estática usando un objeto y '.', pero se recomienda invocar a los miembros estáticos usando el nombre de la clase y el operador de resolución de ámbito.

Solo se permite que las funciones miembro estáticas accedan a miembros de datos estáticos u otras funciones miembro estáticas; no pueden acceder a los miembros de datos no estáticos ni a las funciones miembro de la clase.

#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(); 
} 

Salida:

Welcome to Apple!

Restringir el ámbito de acceso

static también cumple la función de restringir el ámbito de acceso (de forma parecida a un espacio de nombres anónimo). Procedente de la 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);
}

g++ compila con normalidad los dos archivos de código anteriores e imprime Hello World!, pero si añades static a msg en source1.cpp, se produce un error de compilación 'undefined reference to msg':

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

Enlace interno de static (restringir el ámbito de acceso)

Gracias a la issue #142 por señalarlo: cuando static califica a una variable global o a una función, también cumple el papel de restringir el ámbito de acceso: cambia su enlace de externo a interno, con un efecto similar al de un espacio de nombres anónimo:

  • Variable global sin static: otras unidades de traducción pueden acceder a ella mediante una declaración extern;
  • Variable global/función static: visible solo en la unidad de traducción actual; ni siquiera una declaración extern puede enlazarla (undefined reference).

En el C++ moderno se recomienda más usar un espacio de nombres anónimo para expresar "visible solo en este archivo" (también vale para los tipos), pero entender esta faceta de static es muy importante al leer código antiguo.

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

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

Preguntas frecuentes

¿En qué se diferencia una global static de una global normal?

La global static tiene enlace interno: solo es visible en su unidad de traducción. La global normal es visible entre archivos y propensa a conflictos de símbolos.

¿Cuándo se inicializa una variable local static?

Una sola vez, la primera vez que el control pasa por su definición; desde C++11 esa inicialización es thread-safe, y su vida dura hasta el final del programa.

¿Una función miembro static puede acceder a miembros no estáticos?

No. No tiene puntero this, por lo que solo puede usar miembros estáticos.

Temas relacionados

Comentarios