2.- C++: UN C “MEJOR”

 2.1 Comentarios

C++ soporta dos tipos de comentarios:
1. Viejo estilo C: Entre /* y */.
2. Nuevo estilo C++: Comienzan con //. Su efecto termina cuando se alcanza el final de la línea actual.

2.2 Identificadores

Son los nombres elegidos para las variables, constantes, funciones, clases y similares. El primer carácter debe ser una letra o un subrayado. El resto del nombre puede contener dígitos. Los identificadores que comienzan con dos subrayados están reservados para uso interno del compilador C++.

2.3 Constantes

C++ permite utilizar varios tipos de constantes:
1. Constantes enteras      44 0 -345
2. Constantes enteras muy grandes. Se identifican situando una L al final de la constante entera         33L  -105L
3. Constantes octales o hexadecimales. Un 0 a la izquierda indica una constante octal y un 0x o bien 0X indican una constante hexadecimal
         0 02 077 0123 equivalen a 0 2 63 83 en octal
         0x0 0x2 0x3F 0x53 equivalen a 0 2 63 83 en hexadecimal
4. Constantes reales (coma flotante)   0.0 3.1416 -99.2
C++ permite especificar constante de coma flotante de simple precisión (sufijo f o F) y doble precisión larga (sufijo l o L).  32.0f 3.1416L
5. Constantes carácter     'z' '5'
6. Constantes cadena     "hola"   "hoy es lunes"

 2.4 Tipos de datos

C++, igual que C, contiene tipos fundamentales y tipos derivados o estructurados.
Los fundamentales son: int, char, long int, float, double, long double.

- Tipo vacío. El tipo vacío (void) se utiliza principalmente para especificar:
                  * Funciones que no devuelven valores.
                  * Punteros void, que referencian a objetos cuyo tipo es desconocido.

- Tipos enumerados. Un tipo enumerado o enumeración está construido por una serie de constantes simbólicas enteras. Los tipos enumerados se tratan de modo ligeramente diferente en C++ que en ANSI C. El nombre de la etiqueta enum se considera como un nombre de tipo igual que las etiquetas de struct y union. Por tanto se puede declarar una variable de enumeración, estructura o union sin utilizar las palabras enum, strcut o union.
C define el tipo de enum de tipo int. En C++, sin embargo, cada tipo enumerado es su propio tipo independiente. Esto significa que C++ no permite que un valor int se convierta automáticamente a un valor enum. Sin embargo, un valor enumerado se puede utilizar en lugar de un int.

    Ej.  enum lugar{primero,segundo,tercero};
                  lugar pepe=primero; //correcto
                  int vencedor=pepe;  //correcto
                  lugar juan=1;       //incorrecto
La última sentencia de asignación es aceptable en C pero no en C++, ya que 1 no es un valor definido en lugar.

- Tipos referencia. Las referencias son como alias. Son alternativas al nombre de un objeto. Se define un tipo referencia haciéndole preceder por el operador de dirección &. Un objeto referencia, igual que una constante debe ser inicializado.

                  int a=50;
                  int &refa=a;  //correcto
                  int &ref2a;   //incorrecto: no inicializado
Todas las operaciones efectuadas sobre la referencia se realizan sobre el propio objeto:
                  refa+=5; equivale a sumar 5 a a, que vale ahora 55
                  int *p=&refa; inicializa p con la dirección de a

 2.5 Operadores especiales de C++

:: Resolución de ámbito (o alcance)
.* Indirección (eliminación de referencia directa) un puntero a un miembro de una clase
->* Indirección (eliminación de referencia directa) un puntero a un miembro de una clase
new Asigna (inicializa) almacenamiento dinámico
delete Libera almacenamiento asignado por new

2.6 Declaraciones y definiciones

Los términos declaración y definición tienen un significado distinto aunque con frecuencia se intercambian.
Las declaraciones se utilizan para introducir un nombre nombre al compilador, pero no se asigna memoria. Las definiciones asignan memoria.
En C++ cuando se declara una estructura se proporciona su nombre al compilador pero no se asigna memoria. Cuando se crea una instancia de la estructura es cuando se asigna memoria.
En C todas las declaraciones dentro de un programa o función deben hacerse al principio del programa o función; en otras palabras las declaraciones dentro de un ámbito dado deben ocurrir al principio de ese ámbito.. Todas las declaraciones globales deben aparecer antes de cualquier función y cualquier declaración local debe hacerse antes de cualquier sentencia ejecutable.
C++, por el contrario, permite mezclar datos con funciones y código ejecutable: trata una declaración como un tipo de sentencia y permite situarla en cualquier parte como tal. Esta característica de C++ es muy cómoda ya que permite declarar una variable cuando se necesite e inicializarla inmediatamente.
El ámbito de una variable es el bloque actual y todos los bloques subordinados a él. Su ámbito comienza donde aparece la declaración. Las sentencias C++ que aparecen antes de la declaración no pueden referirse a la variable incluso aunque aparezcan en el mismo bloque que la declaración de la variable.

2.7 Moldes (cast)

C++ soporta dos formas diferentes de conversiones forzosas de tipo explícitas:

 int f=0;
long l= (long) f; molde tradicional, tipo C
long n = long (f); molde nuevo, tipo C++

La sintaxis  nombre_tipo (expresión) se conoce como notación funcional y es preferible por su legibilidad.

2.8 El especificador constante (const)

Una constante es una entidad cuyo valor no se puede modificar, y en C++, la palabra reservada const se utiliza para declarar una constante.
                  const int longitud = 20;
                  char array[longitud];  // válido en C++ pero no en C

Una vez que una constante se declara no se puede modificar dentro del programa.
En C++ una constante debe ser inicializada cuando se declara, mientras que en ANSI C, una constante no inicializada se pone por defecto a 0.
La diferencia más importante entre las constantes en C++ y C es el modo como se declaran fuera de las funciones. En ANSI C se tratan como constantes globales y se pueden ver por cualquier archivo que es parte del programa. En C++, las constantes que se declaran fuera de una función tienen ámbito de archivo por defecto y no se pueden ver fuera del archivo en que están declaradas. Si se desea que una constante se vea en más de un archivo, se debe declarar como extern.
En C++ las constantes se pueden utilizar para sustituir a #define.

En C

En C++

#define PI 3.141592   const PI = 3.141592
#define long 128          const long = 128       

2.9 Punteros y direcciones de constantes simbólicas

No se puede asignar la dirección de una constante no simbólica a un puntero no constante, pero sí se puede desreferenciar el puntero y cambiar el valor de la constante.
                      const int x=6;
                      int *ip;
                      ip = &x;    //error
                      *ip=7;

Punteros a un tipo de dato constante
Se puede declarar un puntero a un tipo de dato constante pero no se puede desreferenciar.
                    const int x=6;
                    const int *ip;   //puntero a una constante entera
                    int z;
                    ip=&x;
                    ip=&z;
                    *ip=10;     //error: no se puede desreferenciar este tipo de puntero y modificar z
                    z=7;          //válido: z no es una constante y se puede cambiar

El puntero a un tipo constante es muy útil cuando se desea pasar una variable puntero como un argumento a una función pero no se desea que la función cambie el valor de la variable a la que está apuntada.

         struct ejemplo
         {
                  int x;
                  int y;
         };
         void funcion(const ejemplo *);
         void main()
         {
           ejemplo e={4,5};
           funcion(&e);   //convertirá un puntero no constante a un puntero const
         }
         void funcion(const ejemplo *pe)
         {   ejemplo i;
             i.x=pe->x;
             i.y=pe->y;
             pe->x=10;   }   // error: no se puede desreferenciar pe

Punteros constantes
Se puede definir una constante puntero en C++. Las constantes puntero se deben inicializar en el momento en que se declaran. Se leen de derecha a izquierda.

         void main()
         {
           int x=1,y;
           int *const xp= &x;  // xp es un puntero constante a un int
           xp=&y;     // error: el puntero es una constante y no se puede asignar un nuevo
                               valor a punteros constantes
           *xp=4;      }

2.10 El especificador de tipo volatile

La palabra reservada volatile se utiliza sintácticamente igual que const, aunque en cierto sentido tiene sentido opuesto.
La declaración de una variable volátil indica al compilador que el valor de esa variable puede cambiar en cualquier momento por sucesos externos al control del programa. En principio, es posible que las variables volátiles se puedan modificar no sólo por el programador sino también por hardware o software del sistema (rutina de interrupción).
                                              volatile int puerto;

2.11 Sizeof (char)

En C, todas las constantes char se almacenan como enteros. Esto significa que en C un carácter ocupa lo mismo que un entero. En C++ un char se trata como un byte, y no como el tamaño de un int. Por ejemplo en una máquina con una palabra de 4 bytes sizeof('a') se evalúa a 1 en C++ y a 4 en C.

2.12 Punteros a void

En C, una variable puntero siempre apunta a un tipo de dato específico, de modo que el tipo de dato es importante para aritmética de punteros. Si se intenta inicializar una variable puntero con el tipo de dato incorrecto, el compilador genera un mensaje de error. En C se pueden moldear los datos al tipo de dato correcto:

         void main()
         {
           int a=1,*p;
           double x=2.4;
           p=&a;   //válido: puntero y variable son del mismo tipo
           p=&x;   //error
           p=(int *)&x; //válido
         }

En C++ se puede crear un puntero genérico que puede recibir la dirección de cualquier tipo de dato.
         void main()
         {   void *p;
             int a=1;
             double x=2.4;
             p=&a;
             p=&x;   }

No se puede desrefernciar un puntero void.
         void main()
         {  void *p;
           double x=2.5;
           p=&x;
           *p=3.6;    // error: se desreferencia a un puntero void
         }

2.11 Salidas y entradas

Las operaciones de salida y entrada se realizan en C++, al igual que en C, mediante flujos (streams) o secuencias de datos. Los flujos estandar son cout (flujo de salida) y cin (flujo de entrada). La salida fluye normalmente a la pantalla y la entrada representa los datos que proceden de teclado. Ambos se pueden redireccionar.

1. Salida
El flujo de salida se representa por el identificador cout, que es en realidad un objeto. El operador << se denomina operador de inserción y dirige el contenido de la variable situada a su derecha al objeto situado a su izquierda. El equivalente en C de cout es printf.
El archivo de cabecera iostream.h contiene las facilidades standard de entrada y salida de C++.
En C++, los dispositivos de salida estandar no requieren la cadena de formato.
Se pueden utilizar también diferente tipos de datos, enviando cada uno de ellos a la vez al flujo de salida. El flujo cout discierne el formato del tipo de dato, ya que el compilador C++ lo descifra en el momento de la compilación.
El operador de inserción se puede utilizar repetidamente junto con cout.

         include <iostream.h>
         void main()
         {
           int a=4;
           float b=3.4;
           char *texto="hola\n";
           cout<< "entero " << a << " real " << b << " mensaje " << texto;
         }

Salida con formato
C++ asocia un conjunto de manipuladores con el flujo de salida, que modifican el formato por defecto de argumentos enteros. Por ejemplo, valores simbólicos de manipuladores son dec, oct y hex que visualizan representaciones decimales, octales y hexadecimales de variable

2. Entrada
C++ permite la entrada de datos a través del flujo de entrada cin. El objeto cin es un objeto predefinido que corresponde al flujo de entrada estandar. Este flujo representa los datos que proceden del teclado. El operador >> se denomina de extracción o de lectura de. Toma el valor del objeto flujo de su izquierda y lo situa en la variable situada a su derecha.

2.12 El operador de resolución de ámbito ::

C es un lenguaje estructurado por bloques. C++ hereda la misma noción de bloque y ámbito. En ambos lenguajes, el mismo identificador se puede usar para referenciar a objetos diferentes. Un uso en un bloque interno oculta el uso externo del mismo nombre. C++ introduce el operador de resolución de ámbito o de alcance.
El operador :: se utiliza para acceder a un elemento oculto en el ámbito actual. Su sintaxis es
            :: variable

Ejemplo:
         #include <iostream.h>
         int a;
         void main()
         {
           float a;
           a=1.5;
           ::a=2;
           cout << "a local " << a << "\n";
           cout << "a global " << ::a << "\n";
         }
Este programa visualiza:                      a local 1.5
                                                                 a global 2
Este operador se utilizará también en la gestión de clases.

2.13 Estructuras y uniones

Los tipos definidos por el usuario se definen como estructuras, uniones, enumeraciones o clases. Las estructuras y uniones son tipos de clase (clase, es el tipo de dato fundamental en la programación orientada a objetos).
El tipo struct permite agregar componentes de diferentes tipos y con un solo nombre. Las estructuras en C++ se declaran como en C:

                      struct datos
                          {
                            int num;
                            char nombre[20];
                          };
El nuevo tipo de dato definido puede tener instancias que se declaran:
                  datos persona;                       //declaración C++
                  struct datos persona;             // declaración C

En C++ debe evitarse el uso de typedef.
El mismo convenio aplicado a las estructuras, se aplica a las uniones.
Un tipo especial de unión se ha incorporado a C++ :unión anónima. Una unión anónima declara simplemente un conjunto de elementos que comparten la misma dirección de memoria; no tiene nombre identificador y se puede acceder directamente a los elementos por su nombre. Un ejemplo:
                 
      union
                          {
                            int i;
                            float f;
                          };

Tanto i como f comparten la misma posición de memoria. A los miembros de esta unión se puede acceder directamente en el ámbito en que está declarada. Por tanto, en el ejemplo, la sentencia i=3 sería aceptable.
Las uniones anónimas son interesantes en el caso en que se defina una unión en el interior de una estructura:

                      struct registro
                             {
                                   union
                                            {
                                              int num;
                                              float salario;
                                            };
                                   char *telefono;
                             };
                        registro empleado;

Para acceder al nombre de un campo dentro de esta estructura:
                        
empleado.sueldo;

2.14 Asignación dinámica de memoria: new y delete

En C la asignación dinámica de memoria se manipula con las funciones malloc() y free(). En C++ se define un método de hacer asignación dinámica utilizando los operadores new y delete.
En C:
        
void main()
         {
           int *z;
           z= (int*) malloc(sizeof(int));
           *z=342;
           printf("%d\n",*z);
           free(z);
        
}

En C++:
        
void main()
         {
           int *z=new int;
           *z=342;
           cout << z;
           delete z;
         }

El operador new está disponible directamente en C++, de modo que no se necesita utilizar ningún archivo de cabecera; new se puede utilizar con dos formatos:
                  new tipo                          // asigna un único elemento
                 
new tipo[num_eltos]       // signa un array

Si la cantidad de memoria solicitada no está disponible, el operador new proporciona el valor 0.
El operador delete libera la memoria signada con new.
                  delete variable
                  delete [n] variable

 new es superior a malloc por tres razones:
1. new conoce cuánta memoria se asigna a cada tipo de variable.
2. malloc() debe indicar cuánta memoria asignar.
3. new hace que se llame a un constructor para el objeto asignado y malloc no puede.

delete produce una llamada al destructor en este orden:
         1. Se llama al destructor
         2. Se libera memoria

delete es más seguro que free() ya que protege de intentar liberar memoria apuntada por un puntero nulo.

dAnterior

Indice C++

Siguiente a