Está en la página 1de 7

4.5.

1 Declaración de estructuras
§1 Sinopsis
Lo mismo que con el resto de las clases ( 4.11), el proceso de usar una estructura C++
comprende en realidad tres pasos: definir la clase; crear un objeto, e iniciar el objeto.
§2 Definir la clase
En contra de lo que ocurre con el resto de los tipos, que están pre-definidos en el lenguaje. Por
ejemplo, al declarar char ch; ya se sabe exactamente que cosa es ch, en este caso hay que definir
previamente el tipo. Los tipos estructura se declaran mediante la palabra clave struct. Sería algo
así como:
struct Punto;
struct Punt2 {int x; int y; int z; };
La primera sentencia es una declaración incompleta (ver más abajo); la segunda es una definición
completa de una nueva clase tipo struct denominado Punt2; tiene tres componentes
perfectamente definidos (tres int: x, y, z respectivamente). Como puede verse, los componentes
se determinan de forma análoga a los parámetros de las funciones, determinando tipo y nombre.
Aquí es imprescindible el punto y coma ";" para separar los miembros (sin olvidar poner otro
después del último).

§2.1 Ya hemos señalado que en C++ las estructuras son un tipo de clases; entonces, si nos
referimos a la terminología de la POO diríamos que en esta fase estamos definiendo la clase. El
conjunto de declaraciones dentro de los corchetes {...; ...; ...; } declara los nombres y tipos de sus
miembros. Los miembros pueden ser de cualquier tipo con una excepción:
§2.2 Un miembro no puede ser la estructura que se declara porque daría lugar a una declaración
circular (lo definido está dentro de su definición). Ejemplo:
struct mystr { mystr s }; // Ilegal
§2.3 Uno, o varios, de los miembros puede ser un puntero a la estructura que se está declarando.
Ejemplo:
struct mystr { mystr *ps } // Ok: Correcto
Nota: esta interesantísima posibilidad constituye la base de estructuras auto referenciadas; una
técnica de programación que tiene amplias posibilidades de aplicación. Por ejemplo, listas
enlazadas y árboles ( 4.5.8).

§2.4 También es posible que los miembros de una estructura sean a su vez estructuras
previamente definidas, dando lugar a estructuras anidadas. Por ejemplo:
struct Punto {
int x; int y;
};
struct Linea {
struct Punto p1;
struct Punto p2;
} c1;
declara Linea como un tipo struct con dos miembros, cada uno de los cuales es un tipo struct
Punto.
Nota: en C, un miembro no puede ser del tipo "función devolviendo...". Es decir, las funciones
no pueden ser miembros de la estructuras C (de lo contrario serían clases). En cambio, sí están
admitidos los "punteros a función devolviendo..." (ya que son variables, no métodos). Las
estructuras C++ sí pueden incluir funciones miembro (de hecho son clases), además, en C++ la
palabra struct puede omitirse.

§2.5 Es importante tener en cuenta que, en este punto (definición), solo está permitido señalar
tipo y nombre de los miembros, sin que se pueda efectuar ninguna asignación; ni aún en el caso
de que se trate de una constante [1]. Por ejemplo, las definiciones que siguen serían ilegales, pues
todas implican una asignación en la definición del segundo miembro:
struct Str {int x; int y = 2; }; // Error!
struct Str {int x; const int y = 3; }; // ídem
struct Str {int x; char c = 'X'; }; // ídem
struct Str {int x; char * st = "Hola"; }; // ídem
struct Str {int x; "Hola"; }; // ídem
struct Str {int x; int a[2] = {3, 4};}; // ídem

§3 Crear un objeto (instanciar la clase)


Un segundo paso es declarar una variable como perteneciente al nuevo tipo. Del mismo modo
que para declarar una variable ch como de tipo char declarábamos: char ch;, en este caso, para
declarar una variable st como estructura tipo punto se utiliza:
struct Punto pt; // C y C++
En C++ no es necesario señalar que Punto es una estructura (suponemos que ya lo sabe el
compilador por las sentencias anteriores), de forma que si no existe ninguna otra variable punto
en el mismo ámbito de nombres, no hay ambigüedad y se puede poner directamente:
Punto pt; // C++
Usando la terminología de la POO diríamos que estamos instanciando la clase, es decir, creando
un objeto concreto pt, con espacio en memoria, que pertenece a (es derivado de) dicha clase.
Dichos objetos sí pueden ser asignados con valores concretos en sus miembros.
§3.1 Advertir que cada declaración de (tipo de) estructura introduce un nuevo tipo, distinto
de los demás (una nueva clase), de forma que las declaraciones:
struct StA {
int i,j;
} a, a1;
struct StB {
int i,j;
} b;
definen dos tipos de estructura distintas: StA y StB; los objetos a y b1 son del tipo StA, pero a y
b son de tipo distinto.
Desde la óptica de la POO la frase anterior se enunciaría como sigue: "definen dos clases
distintas, StA y StB; los objetos a y b1 son instancias de StA, pero b lo es de la clase StB. Por
tanto, a y b son objetos de tipo distinto.

§3.2 De la misma forma que ocurre con el resto de variables, puede declararse más de un
elemento en la misma sentencia:
struct Punto p1, p2, p3,... pn;
sin embargo, de una variable de tipo estructura no es posible derivar nuevas variables, es decir no
es lícita la sentencia que sigue (utilizando la terminología de C++ lo enunciaríamos diciendo: de
un objeto no puede instanciarse otro objeto).
struct p1, p11, p12, p13,... p1n; // NO!!
§4 Iniciar el objeto
Un tercer paso es inicializar dicha variable. Del mismo modo que para iniciar ch se realizaba una
asignación del tipo: ch = 'x', en este caso se utiliza la asignación (análoga a la de matrices):
st = { 12, 25, 3};
Los pasos 2 y 3 se pueden realizar en la misma sentencia. Por ejemplo:
struct punto st = { 12, 25, 3};
También puede realizarse los tres pasos en una misma sentencia:
struct punto { int x; int y; intz; } p1 = { 12, 25, 3};

Una vez definido el nuevo tipo, pueden declararse punteros y matrices de estructuras de dicho
tipo. Por ejemplo:
struct stA { ... }; // define la estructura tipo stA
struct stA st, *pst, arst[10];
La segunda línea declara que st es una estructura de tipo stA; que pst es un puntero a dicho tipo,
y que arst es un array de 10 estructuras tipo stA.

§4.1 Como se verá a continuación , es posible incluso declarar estructuras sin asignar un
nombre al tipo correspondiente. Por ejemplo:
struct { ... } st, *pst, arst[10];
§5 Espacio de nombres de estructuras
Los nombres de tipos de estructura comparten el espacio de nombres con las uniones y
enumeraciones (las enumeraciones dentro de una estructura están en un espacio de nombres
diferente). Ver L.4 y L.11 en el ejemplo.
Los nombres de estructura están en un espacio de nombres diferente que el de nombres de tipos
de estructura y nombres de etiqueta (en C++ solo si no tienen un constructor). Ver L.8 y L.18 del
ejemplo que sigue .
Los miembros de estructuras disponen de un espacio de nombres cerrado y particular (espacio de
nombres de miembros de clases), de forma que sus nombres se pueden repetir con los de
miembros de otras estructuras o con los de otros espacios (ver L.6, L.7, L.12 y L.16 del ejemplo
).
La consecuencia es que dentro del mismo ámbito, los nombres de estructuras y uniones deben
ser únicos (ambos comparten el espacio de nombres de clases), aunque no hay inconveniente que
compartan los nombres con los miembros de los otros tres espacios: El de etiquetas; el de
miembros (de clases) y el de enumeraciones [3]. ( 4.1.11 Espacion de Nombres y 4.11.4
Ambito de nombres de clase).
§5.1 Ejemplo

goto s;
...
s: // L.3 Etiqueta
struct s { // L.4 OK: nombres de tipo_de_estructura y etiqueta en
// espacios diferentes
int s; // L.6 OK: nombres miembro de estructura en espacio privado
float s; // L.7 ILEGAL: nombre de miembro duplicado
} s; // L.8 OK: nombre_de_estructura en espacio diferente de
// nombre de etiqueta (L.3) y de tipo_de_estructura (L4)
// En C++, esto solo es posible si s no tiene un constructor
union s { // L.11 ILEGAL: nombre duplicado con el de tipo s (L.4)
int s; // L.12 OK: nuevo espacio de miembros
float f;
} f; // L.14 OK: espacio diferente que el de miembros (ver L.8)
struct t {
int s; // L.16 OK: nuevo espacio de miembros
...
} s; // L.18 ILEGAL: nombre duplicado con el de estructura s (L8)
§6 Declaraciones incompletas
Las declaraciones incompletas, conocidas también como declaraciones anticipadas o
adelantadas; consisten en que un puntero a una estructura tipoA puede aparecer en la
declaración de otra, tipoB antes que tipoA haya sido declarada. Ejemplo:
struct A; // declaración anticipada
struct B { struct A *pa };
struct A { struct B *pb };

En este caso, la primera declaración de A se denomina incompleta o anticipada, porque no existe


definición para ella (cuales son sus miembros). Este tipo de declaración sería correcta aquí,
porque en la declaración de B no se necesita conocer el tamaño de A (solo el de un puntero a
estructura).
Más sobre declaraciones adelantadas de clases en 4.11.4.

§7 Hay que advertir que en C++ es muy frecuente utilizar typedefs en la declaración de
estructuras. De hecho, los ficheros de cabecera de los compiladores C++ están repletos de ellos.
Es muy frecuente que utilicen expresiones como [4]:
typedef struct {
unsigned char *curp; // Current active pointer
unsigned char *buffer; // Data transfer buffer
int level; // fill/empty level of buffer
int bsize; // Buffer size
unsigned short istemp; // Temporary file indicator
unsigned short flags; // File status flags
wchar_t hold; // Ungetc char if no buffer
char fd; // File descriptor
unsigned char token; // Used for validity checking
} FILE; // This is the FILE object
Por tanto, es posible escribir sentencias como:
#include <stdio.h>

int main(void) {
FILE *in, *out; // define punteros a estructuras FILE
...
Sin embargo, dentro del mismo ámbito de nombres, C++ no permite que una estructura (o clase)
tenga el mismo nombre que un typedef declarado para definir un tipo diferente. Ejemplo:
typedef void (*C)();
...
class C { // Error declaración múltiple para C.
...
};
§8 Tipos anónimos
El nombre de un tipo de estructura puede omitirse, teniéndose lo que se llama un tipo anónimo
(sin nombre). Pueden utilizarse en declaraciones de componentes separados por comas cuando se
quiere indicar que los componentes son (o derivan de) un tipo de estructura determinado.
Presenta el problema de que al no poderse referir más al tipo (por no tener nombre), no pueden
declararse más objetos adicionales en ningún otro sitio. Ejemplo:
struct { ..; ..; ..; } s, *ps, arrs[10]; // tipo sin nombre

Es posible crear un typedef al mismo tiempo que se declara una estructura, con o sin nombre,
como se ve en los ejemplos. Generalmente no se necesitan un typedef y un nombre al mismo
tiempo, ya que cualquiera de ellos sirve para las declaraciones.
typedef struct mystruct { ..;..; } MST;
MST s, *ps, arrs[10]; // igual que struct mystruct s, etc.
typedef struct { ..; ..; } YST; // sin nombre
YST y, *yp, arry[20];

Cuando son miembros de clases, las estructuras y uniones anónimas son ignoradas durante la
inicialización.
Nota: el ANSI C++ solamente permite estructuras anónimas que declaren un objeto. Por su
parte, el ANSI C no permite estructuras anónimas, y el compilador C++ de Borland permite
varios tipos de estructuras anónimas que extienden el estándar ANSI ( 4.11.3a).

§8.1 Debido a que no hay propiedades de instancia, la sintaxis C++ para las estructuras anónimas
no permite referenciar un puntero this ( 4.11.6). Por consiguiente, mientras que una estructura
C++ puede tener funciones miembro, las estructuras anónimas C++ no pueden tenerlas. Los
miembros de las estructuras anónimas pueden ser accedidos directamente en el ámbito en que las
estructuras han sido declaradas sin la necesidad de utilizar la sintaxis x.y o p->y. Por ejemplo:
struct my_struct {
int x;
struct {
int i;
};
inline int func1(int y) { return y + i + x; }
} S;

int main() {
S.x = 6; S.i = 4;
int y = S.func1(3);
printf(“y is %d“, y);
return 0;
}
§8.2 Estructuras anónimas anidadas
Borland C++ permite estructuras anónimas y que no sean usadas para declarar un objeto o
cualquier otro tipo. Tienen la forma que se indica:
struct { lista-de-miembros };

Las estructuras anónimas pueden ser anidadas, es decir, declaradas dentro de otra estructura,
unión o clase. En estos casos, la estructura externa debe tener nombre. Por ejemplo:
struct my_struct {
int x;
struct { // estructura anónima anidada dentro de my_struct
int i;
};
inline int func1(int y);
} S;

Para compatibilidad con el compilador Visual C++ de Microsoft, el compilador Borland C++
permite declarar una estructura con nombre que no declara ningún objeto. Estas estructuras
huérfanas deben ser anidadas. Por ejemplo:
struct Direccion {
char calle[25];
int numero;
};

struct Persona {
char nombre[35]
struct Direccion; // estructura huérfana
} candidato; // una instancia de Persona
candidato.numero = 10;

Inicio.

[1] Si nos referimos a C++, se podrían hacer asignaciones iniciales, pero a través del constructor
de la clase.
[3] No confundir los nombres de las enumeraciones con los nombres de los enumeradores.
[4] Definición tomada del fichero de cabecera <stdio.h> de la Librería Estándar ( 5).
Inicio

|Índice| Copyright © 1990-2010 Zator Systems.

También podría gustarte