Disponible la nueva versión "donationware" 7.3 de OrganiZATOR
Descubre un nuevo concepto en el manejo de la información.
La mejor ayuda para sobrevivir en la moderna jungla de datos la tienes aquí.

Curso C++

[Home]  [Inicio]  [Índice]


 Prev.

2.2 Los Tipos C++ (II)

§5 Los tipos C++

Aunque las cuestiones de clasificación suelen ser un tanto artificiosas, dependiendo de la característica distintiva que se aplique, los tipos de datos C++ pueden clasificarse como sigue:

§5.1 Tipos básicos

También llamados fundamentales, primitivos y escalares. No tienen "descomposición", están predefinidos en el lenguaje. Su álgebra, es decir, las operaciones que les son permitidas, también están preconstruidas en el lenguaje, que dispone así mismo de constructores y destructores por defecto para ellos [3]. Su clasificación es la siguiente:

  • Asimilables a enteros

    • carácter  (char)

    • entero (int)

    • booleano (bool)

    • enumeraciones (enum)

    • punteros (no tienen una palabra clave específica, sino un símbolo *, -calificador de tipo-)

  • Fraccionarios (float, double)

  • Ausencia de dato (void)

Más detalles sobre los tipos básicos en: ( 2.2.1)

§5.2  Tipos extendidos:

Son "adaptaciones" de detalle sobre los tipos básicos para mejor adaptarse a necesidades específicas.

  • largo (long)

  • corto (short)

  • con signo (signed)

  • sin signo (unsigned)

Los enteros y fraccionarios (en todas sus variaciones long, signed, etc) se conocen colectivamente como tipos numéricos.

§5.3  Tipos compuestos

Aparte de los anteriores, C++ soporta tipos compuestos (también denominados tipos-clase). Son compuestos o agregados de tipos básicos, por esta razón se les denomina también tipos agregados o abstractos ADTs ("Abstract data types"). El "material" de que están compuestos son los tipos básicos, bien en estado "puro" o en sus diversas "adaptaciones". El proceso es recursivo, de forma que un tipo complejo puede contener miembros que son a su vez tipos complejos y así sucesivamente.

Desde el punto de vista semántico la gramática C++ establece como tipos compuestos ("Compound types") los siguientes:

  • Matrices de objetos de cualquier tipo ( 4.3).

  • Funciones, que aceptan parámetros de ciertos tipos y devuelven void u objetos (o referencias a objetos) de cierto tipo ( 4.4).

  • Punteros a-void;  punteros a-objetos, o punteros a-función (incluyendo miembros estáticos de clases) de un tipo determinado ( 4.2).

  • Punteros a miembros no-estáticos de clases (que señalan miembros de un tipo determinado dentro de objetos de una clase determinada 4.2.1g1).

  • Referencias a objetos o funciones de un tipo determinado ( 4.2.3).

  • Clases ( 4.11).

  • Uniones ( 4.7).

  • Enumeraciones ( 4.8).


En la POO los tipos definidos por el usuario, reciben el nombre genérico de clases, entidades abstractas cuyos miembros son aglomerados de variables de distintos tipos (propiedades) y las funciones (métodos) que las manejan, inicializan y destruyen ( 4.11).  Este capacidad de crear nuevos tipos de datos de cualquier nivel de complejidad y sus operaciones, es precisamente una de las características de la POO y se considera uno de los mayores avances en la tecnología de los lenguajes de computación.

Nota: existen dos mecanismos para generar este proceso recursivo (crear nuevos tipos complejos a partir de otros): la composición y la herencia; ambos son analizados en detalle al tratar de las clases ( 4.11.1).

Aunque desde el punto de vista de su Rvalue los punteros son asimilables a enteros (alojan direcciones de memoria), la gramática del lenguaje los distingue según el tipo de objeto al que apuntan, por lo que puede considerarse que constituyen un tipo con múltiples subtipos:  Punteros-a-int; punteros-a-char; punteros-a-void;  punteros-a-clase; punteros-a-función, Etc. Virtualmente existen tantas clases de punteros como tipos de objetos puedan ser señalados.

§5.4 Tipos incompletos

Existen ocasiones en las que el lenguaje permite la declaración incompleta de tipos; entidades de las que el compilador no tiene por el momento toda la información que sería necesaria para una utilización normal, pero que a ciertos efectos puede ser suficiente. Son los llamados tipos incompletos ( 4.1.2). Su principal característica es que tanto su tamaño como el patrón de bits correspondiente son desconocidos para el compilador.

§5.5 Tipos calificados

Los tipos básicos y complejos descritos anteriormente se denominan conjuntamente tipos no-calificados. La razón de esta denominación es que, en C++ existen ciertos especificadores (denominados calificadores) que al ser aplicados a un tipo, produce un tipo nuevo (tipo calificado) con propiedades y reglas de operación distintas del primitivo, pero con una representación interna exactamente igual a la del tipo no-calificado.

Estos cualificadores son las palabras-clave const, volatile y const volatile.  Podemos suponer que la aplicación de estos calificadores supone la existencia de una especie de universo paralelo, en el que para cada tipo no-calificado puede existir la correspondiente versión const ( 3.2.1c), volatile ( 3.2.1d), o const volatile. Aunque la descripción de cada uno de estas palabras-clave se realiza en el apartado correspondiente, tienen ciertas características de actuación comunes:

  • Un tipo complejo (por ejemplo una estructura) no se considera un tipo cualificado porque algunos de sus miembros lo sean.

  • La calificación de un tipo complejo implica que todos sus propiedades tienen la misma calificación salvo que sean estáticas o tengan un calificador específico.

  • Un calificador aplicado a una matriz no altera el tipo de la matriz en sí misma, sino al tipo de sus miembros.


Recordar que C++ dispone de un sistema que permite obtener el tipo de una entidad en tiempo de ejecución (mecanismo RTTI). Sin embargo, este mecanismo no permite obtener la "calificación" en su caso, del objeto. Para ciertas cuestiones la transformación de un tipo calificado en no calificado, y viceversa, es realizada automáticamente por el compilador en lo que se denominan conversiones triviales ( 2.2.5)

§5.6 Nombres de tipos

Tanto externamente, para el programador que debe utilizarlos, como internamente, para las comprobaciones realizadas por el compilador, y como argumento de los operadores sizeof ( 4.9.13), new ( 4.9.20) o typeid ( 4.9.14), los tipos necesitan un nombre ("Type name") con el que distinguirlos de entre las infinitas posibilidades pueden existir en C++.

Ejemplos:

new char [5];           // char es un nombre de tipo

typeid (float);         // float es un nombre de tipo

sizeof (long double);   // long double es un nombre de tipo

En las declaraciones el nombre del tipo acompaña siempre al nombre de la entidad que se declara (objeto o función):

char mc[5];

float fl;

long double ld;


La gramática C++ denomina type-id [5] al identificador de los tipos, y señala que un type-id es sintácticamente una declaración de un objeto o función de ese tipo al que le falta el nombre de la entidad. Ejemplos:

type-id declaración Descripción del tipo
int int m m es un subtipo de los enteros denominado int ( 2.2.4)
int* int* pi pi es puntero-a-entero
int* [5] int* mi[5] mi es una matriz de cinco punteros-a-entero
int (*)[5] int (* pf)[5] pf es puntero-a-matriz de cinco enteros
int* () int* f1() f1 es una función que no acepta argumentos devolviendo puntero-a-entero
int* (char*) int* f2 (char*) f2 función que acepta un puntero-a-char y devuelve un puntero-a-entero
int (*) (char) int (* f3)(char) f3 puntero-a-función que acepta un char y devuelve un entero

Temas relacionados:

  • Especificador typedef ( 3.2.1a)

  • Designación de tipos en los compiladores ( 4.2.4a2).

§5.7 Tipo de funciones

El tipo de las funciones viene determinada por sus argumentos y por el valor devuelto. En caso de existir argumentos con valores por defecto se considera que estos últimos no tuvieran dichos valores. Ejemplo:

int foo(int = 0);

...

int (* fptr)(int) = &foo;    // Ok!!

int (* fptr)() = &foo        // Error: tipo de &foo y fptr no concuerdan 

§5.8 Tipo de clases

Cada clase constituye un tipo en sí mismo; sin ningún otro tipo de atributo y sin que intervenga su estructura interna en la definición del tipo:

class C { int x; };   // Ok. tipo class C

class C { char c;};   // Error!! tipo ya definido

class D { int x;};     // Ok. tipo class D

La segunda línea es erronea porque dentro de un subespacio de nombres no pueden declararse dos objetos del mismo tipo con el mismo nombre.

§5.9 Tipo de miembros de clase

Es importante señalar que, aparte de la diferencia de tipo introducida por los calificadores (§5.5 ), los miembros no estáticos de clase constituyen a su vez submundos aparte en lo que respecta a los tipos. Por ejemplo: un miembro int m de clase C no se considera del mismo tipo que un int del espacio global o un miembro int m de otra clase D. Un caso análogo ocurre con las funciones y los métodos de clase: una función del espacio global aceptando un int y devolviendo void no es del mismo tipo que un método de la clase C que acepte un int y devuelva void. El cuadro adjunto muestra sendos ejemplos:

type-id declaración Descripción del tipo
int int m m es un int (entero)
int C:: int m   m es miembro int de-la-clase C
int* int* pi pi es un puntero-a-int
int C::* int C::* iptr iptr es puntero-a-miembro int de-la-clase C
int (char*) int f1(char*)  f1 es función que devuelve int y acepta puntero-a-char
int C::(char*) int C::f(char*) f es una función-miembro de C que devuelve un int y recibe un puntero-a-char

La declaración se realiza dentro del cuerpo de la clase

Temas relacionados:
  • Identificación de tipos en tiempo de ejecución RTTI ( 4.9.14)

  • El operador typeid ( 4.9.14)

  • Modelado de tipos ( 4.9.9)

  • La cuestión de los "Tipos" en las plantillas ( 4.12.2)

  Inicio.


[1] C++ es un lenguaje de propósito general que no ha sido especialmente diseñado para la computación numérica, por lo que de forma nativa no dispone de tipos de datos de alto nivel, ni por consiguiente, de sus operaciones. Sin embargo su velocidad de ejecución lo hace muy dotado para todo tipo de aplicaciones de cálculo, además dispone de recursos muy potentes al respecto en su Librería Estándar ( 5).

[2] El tratamiento que hacen de los "Tipos" los diferentes lenguajes si es muy variado. Frente a los fuertemente tipados, como C/C++, existen otros prácticamente sin tipo definido ("Tipeless"), mientras que otro grupo presenta una posición intermedia con una tipología muy simple y permisiva ("Loosely typed").  Un caso extremo está representado por BCPL ( 0.Iw2), uno de los ancestros de C, y una posición intermedia estaría representada por JavaScript, que cuenta solo con cinco tipos distintos y una gran capacidad de adaptación automática entre ellos. En este punto cabe hacer otra observación; en atención a su capacidad de adaptación, más que lenguajes sin tipo ("Tipeless"), algunos autores prefieren decir que se trata de lenguajes con tipos dinámicos o tolerantes ("Dynamic types" o "Tolerant types").

[3] Más detalles respecto a estos constructores para los tipos básicos en el capítulo dedicado al operador new ( 4.9.20).

[4]  Para comprender cabalmente el ejemplo debe consultarse el epígrafe  Punteros en jerarquías de clases ( 4.11.2b1).

[5]  Utilizaremos indistintamente nombre-de-tipo o su acrónimo inglés type-id.

 Prev.