4.1 Iniciar constantes estáticas
Recordemos que excepcionalmente, las constantes estáticas pueden ser iniciadas en el cuerpo de la clase ( 4.11.2a). Es decir, se permiten expresiones del tipo [1]:
class C {
static const int k1 = 2; // Ok: static const float f1 = 2.0; // Ok: static Etiquetas objetos[MAXNUM]; …
};
const int C::k1; cons float C::f1; Etiquetas C::cargos[MAXNUM];
Observe que en este caso aún es necesario declarar el miembro fuera de la clase, aunque no es necesaria aquí su inicialización.
Nota: recordar que es posible sustituir una constante estática entera por un enumerador ( 4.11.2a).
A este respecto tenga en cuenta que los miembros estáticos de una clase global pueden ser inicializados como objetos globales ordinarios, pero solo dentro del ámbito del fichero.
Es oportuno señalar que la inclusión de un constructor explícito en la declaración de la clase no hubiese evitado tener que incluir las tres últimas sentencias para definición de los miembros respectivos. Por ejemplo, el código que sigue daría los mismos errores de compilación que el anterior.
class C {
static y;
public: int x;
static int* p;
static char* c;
static int gety () { return y; }
C () { // constructor por defecto
y = 1;
p = &y;
c = “ABC”;
};
La razón es evidente: el constructor es invocado cuando se instancia un miembro de la clase, mientras que los miembros estáticos (que en realidad “pertenecen” a la clase y no a las instancias), tienen existencia incluso antes de existir ninguna instancia concreta .
Como consecuencia directa, si se incluye una asignación a un miembro estático dentro del constructor, al ser esta asignación posterior a la que se realiza en la definición, los valores indicados en el constructor machacarán a los que existieran en la definición.
Ejemplo
- include <iostream>
using namespace std;
class A {a
public: static int x; // miembro estático
A(int i = 12) { x = i; } // constructor por defecto
}; int A::x = 13; // definición de miembro
int main() { // ==============
cout << “Valor de A.x: “ << A::x << endl; A a1; // Invoca al constructor. cout << “Valor de A.x: “ << A::x << endl; return 0;
}
Salida:
Valor de A.x: 13 Valor de A.x: 12
Para verificar la sucesión de los hechos, construimos otro sencillo experimento, añadiendo algunas instrucciones al ejemplo anterior:
- include <iostream.h>
class C {
static y; // int por defecto
public: int x;
static int* p;
static char* c;
static int gety () { return y; }
C () { // constructor por defecto
y = 1; // iniciadores de “instancia”
x = 3;
p = &y;
c = “ABC”;
}
}; int C::y = 20; // iniciadores de “clase” int* C::p = &C::y; char* C::c = “abc”;
int main () { // ===============
cout << “Valor .y == “ << C::gety() << endl; cout << “Valor .p == “ << *(C::p) << endl; cout << “Valor .c == “ << C::c << endl;
/*cout << “Valor .x == “ << C::x << endl; ERROR:
Member C::x cannot be used without an object in function main() */ C c1; cout << “Valor c1.y == “ << c1.gety() << endl; cout << “Valor c1.p == “ << *(c1.p) << endl; cout << “Valor c1.c == “ << c1.c << endl; cout << “Valor c1.x == “ << c1.x << endl;
}
Salida:
Valor .y == 20 Valor .p == 20 Valor .c == abc Valor c1.y == 1 Valor c1.p == 1 Valor c1.c == ABC Valor c1.x == 3
5 Características de los miembros estáticos
En este sencillo programa comprobamos un buen montón de las características especiales de los miembros estáticos:
Las tres primeras salidas se producen antes de instanciar ningún objeto:
Los miembros estáticos tienen existencia antes que cualquier instancia de la clase.
Los valores iniciales son debidos a los iniciadores de clase.
El intento de construir una cuarta salida siguiendo la pautas de las anteriores con el miembro x no-estático conduce al previsible error de compilación (muy explícito por cierto).