Entidades estáticas en C, C++ y Java

Publicado por

Seguramente más de una vez te has encontrado con la palabra reservada static en diversos lenguajes de programación, entre ellos C, C++ y Java. Si no comprendes muy bien cuál es su funcionamiento, o quieres verificar si tu definición coincide con la mostrada en esta entrada, no dejes de leer.

Definición

Según el lenguaje de programación del que hablemos y la entidad que estemos declarando como estática, será la definición que podremos dar de ella. Sin embargo, a grandes rasgos podemos definir que una entidad estática es…

  • Aquella cuyo tiempo de vida corresponde al tiempo de ejecución del programa. Su inicialización será recordada y, aunque se abandone el bloque en que esta es visible, seguirá estando en memoria disponible para el ámbito en que fue declarada.

Sintaxis general en C

La forma de declarar una entidad estática es la siguiente:

static tipo_de_dato identificador; //Variable
static val_retorno identificador(argumentos); //Función

Ejemplo de variable estática

Para comprender cómo funciona una variable estática analicemos el siguiente ejemplo donde se inicializa una variable estática dentro de una función y, posteriormente, se vuelve a llamar dicha función:


#include <stdio.h>

void funcion(int);

int main(){
    funcion(1);
    funcion(2);
    funcion(3);
    //printf("%d\n", var_est);

    return 0;
}

void funcion(int arg){
    static int var_est = 0;
    var_est += arg;
    printf("argumento=%d | estatica=%d\n", arg, var_est);
}

Salida:


argumento=1 | estatica=1
argumento=2 | estatica=3
argumento=3 | estatica=6

Como puedes darte cuenta, aunque la función termina (es eliminada de la pila de llamadas), cuando vuelve a ser ejecutada, la inicialización de la variable estática es simplemente ignorada puesto que previamente ya fue inicializada y se sigue manteniendo el valor de la llamada anterior.

Intenta quitar las diagonales del comentario en la función principal y recompila el programa… Cuando intentas llamar a la variable estática fuera de la función en que fue declarada, el compilador no puede localizarla a pesar de que técnicamente dicha variable sigue existiendo. Con esto podemos concluir que, aunque en C el tiempo de vida de una variable estática es el tiempo de ejecución del programa, las reglas de ámbitos se siguen aplicando sobre ellas.

¿Dónde están las variables estáticas?

La razón porque estas variables siguen siendo “recordadas” por el programa a pesar de que las funciones donde fueron declaradas terminaron es porque no fueron almacenadas en la pila de llamadas como los demás datos de dichas funciones. En su lugar, dependiendo de cómo fueron inicializadas, son almacenadas en los segmentos .DATA (cuando son inicializadas con un valor diferente a 0) y .BSS (cuando son inicializadas con valor 0). Cuando el programa es compilado, el espacio para las variables estáticas es reservado, a diferencia de otras variables cuyo espacio se asigna cuando la subrutina se almacena en la pila de llamadas o, en otros casos, cuando el usuario lo reservan de forma dinámica durante ejecución.

Funciones estáticas en C

Si una función es declarada como estática, solamente podrá accederse a ella desde el archivo en que fue declarada y su identificador podrá reutilizarse en otros archivos de código fuente sin problemas. Esto nos permite encapsular información en C.

Entidades estáticas en C++

Como sabes, C++ es un lenguaje orientado a objetos, cuando un miembro de una clase es declarado como estático, significa que, sin importar la cantidad de instancias que hagamos de dicha clase, solamente existirá una copia del miembro estático que será compartida por todos los objetos de la clase.

Los métodos estáticos pueden ser llamados sin haber creado una instancia (objeto) de la clase a la que pertenecen si usamos el operador de resolución de ámbito :: .

Ejemplo en C++

En el siguiente ejemplo podemos apreciar cómo se utiliza un método estático y cómo se crea una variable estática en C++:

#include <iostream>
#include <string>

using namespace std;

class Personaje {

  public:

    static int cant_personajes;
    Personaje(string nombre){
        this -> nombre = nombre;
        cant_personajes++;
        cout << "Personaje creado: " << nombre << endl;
    }

    static string AcercaDe(){
        return string("Programa para ejemplificar miembros estáticos\n");
    }

    string DameNombre(){
        return nombre;
    }
 
  private:
    string nombre;
};

int Personaje::cant_personajes = 0; //Fuera de la definición de la clase

int main(){
    cout << Personaje::AcercaDe() << endl;

    Personaje prota(string("Jose"));
    Personaje villano(string("Daniel"));
    Personaje rival(string("Carlos"));

    cout << endl << "Has creado: " << Personaje::cant_personajes << "personajes" << endl;

    return 0;
}

Salida:


Programa para ejemplificar miembros estáticos

Personaje creado: Jose
Personaje creado: Daniel
Personaje creado: Carlos

Has creado: 3 personajes

Variables y métodos estáticos en Java

El funcionamiento y utilidad de las variables y métodos estáticos en Java son casi los mismos que en C++, salvo por un par de diferencias:

  • En Java no puede existir una variable o método estático perteneciente a un subámbito. En su lugar debe de estar en el ámbito de toda la clase en que se encuentre, de otro modo ocurrirá un error, por ejemplo:

static String DiHola() {
    static String saludo = "Hola mundo\n"; //Error
    return saludo;
}
public static void main(String[] args) {
    System.out.println(DiHola());
}

Salida:


Error de compilación

Dicho error ocurre porque intentamos declarar una variable local al método DiHola. Si cambiáramos la ubicación de la variable a fuera del método, no habría ningún problema puesto que así estaría en el ámbito de toda la clase en la que estemos trabajando.

  • En C++ no existen los bloques de instrucciones estáticos a diferencia de Java. Estos bloques son ejecutados cuando se crea la primera instancia de la clase o cuando se utiliza algún miembro estático de ella (sin importar si se creó o no una instancia previamente). Estos bloques se ejecutan solo una vez y tienen prioridad de ejecución sobre constructores. Analicemos el siguiente ejemplo:

public class Principal {
    public static void main(String[] args) {
        System.out.println(A.a);
        System.out.println();

        B o1 = new B(1);
        B o2 = new B(2);
    }
}

class A{
    public static String a = "Falló el ejemplo :(";
    static {
        a = "Éxito! Bloque estático llamado primero";
    }
}

class B{
    B(int val){
        System.out.println("Constructor de objeto " + val + " llamado");
    }
    static {
        System.out.println("Bloque estático de clase B llamado");
    }
}

Salida:


Éxito! Bloque estático llamado primero

Bloque estático de clase B llamado
Constructor de objeto 1 llamado
Constructor de objeto 2 llamado

Cuando intentamos llamar la variable estática de la clase A, primero es ejecutado el bloque estático que modifica el contenido de la cadena que será mostrada en pantalla. Posteriormente creamos 2 instancias de la clase B; al llamar al constructor del primer objeto, primero se ejecuta el bloque estático sobre el constructor. Cuando la segunda instancia es creada, se ignora el bloque estático puesto que ya fue ejecutado con el primer objeto.

Como podrás suponer, el método principal main es estático para poder ser invocado al inicio de la ejecución del programa sin necesidad de crear una instancia de la clase a la que pertenece.

Pros de las variables estáticas ¿Por qué utilizar variables estáticas?

Son muchas las razones por las que podrías usarlas:

  • Quieres mantener el valor de una variable local a una función a pesar de que esta haya salido de la pila de llamadas.
  • Necesitas encapsular información en C.
  • Quieres tener una sola copia de una variable perteneciente a una clase y que esta sea compartida por todos los objetos.
  • Necesitas ejecutar el método de una clase sin necesidad de crear instancias.

El verdadero reto es saber identificar los casos en los que estrictamente sea necesario utilizarlas en lugar de otras alternativas más eficientes.

Contras de las variables estáticas ¿Por qué no utilizar variables estáticas?

  • En los lenguajes como C se vuelve confuso identificar el flujo del programa.
  • Podríamos estar confundiendo su uso con el de otra alternativa más eficiente para la situación en que se trabaje, como un singleton, por ejemplo.
  • Vuelven más complicado el proceso de comunicación (mensajes) entre bloques estáticos y bloques no estáticos de nuestros programas.
  • Violan muchas de las mejores características del paradigma orientado a objetos.

2 comments

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *