Curso de C++ (Página 22a)

pagina021 Principal pagina022b

CAPITULO 22a Funciones III

Aún quedan algunas cosas interesantes por decir sobre las funciones en C++.

Parámetros con valores por defecto

Algunas veces nos puede interesar que ciertos parámetros que necesita una función no sea necesario proporcionarlos siempre. Esto suele suceder cuando esos parámetros casi siempre se usan con un mismo valor. En C++, cuando declaramos una función podemos decidir que algunos sus parámetros sean opcionales. En ese caso tendremos que asignales valores por defecto.

Cuando se llama a la función incluyendo valores para los parámetros opcionales funcionará como cualquiera de las funciones que hemos usado hasta ahora, pero si se omiten todos o algunos de estos parámetros la función trabajará con los valores por defecto que hemos definido.

Por ejemplo:

#include <iostream.h>
 
void funcion(int a = 1);
 
int main() { 
   funcion(19); 
   funcion(); 
}
 
void funcion(int a) { 
   cout << a << endl; 
} 

La primera llamada a "funcion" dará como salida 19, que es el parámetro que le damos explícitamente. La segunda llamada dará como salida 1, que es el valor por defecto.

Sin embargo este método tiene algunas limitaciones:

Por ejemplo:

void funcion1(int a, int b=0, int c= 1); // Legal 
void funcion2(int a=1, int b, int c); // Ilegal 

Los argumentos por defecto empiezan a asignarse empezando por el último.

int funcion1(int a, int b=0, int c=1); 
...
funcion1(12, 10); // Legal, el valor para "c" será 1 
funcion1(12); // Legal, los valores para "b" y "c" serán 0 y 1 
funcion1(); // Ilegal, el valor para "a" es obligatorio 

Funciones con número de argumentos variable

También es posible crear funciones con un número indeterminado de argumentos, para ello la declararemos los argumentos conocidos del modo tradicional, de éste tipo debe existir al menos uno, y los desconocidos se sustituyen por tres puntos (…), del siguiente modo:

int funcion2(int a, float b, …);

Los parámetros se pasan usando la pila, (esto es siempre así, pero normalmente no tendremos que prestar artención a éste hecho). Además es el programador el responsable de decidir el tipo de cada argumento, lo cual limita bastante el uso de esta forma de pasar parámetros.

Para hacer más fácil la vida de los programadores, se incluyen algunas macros en el fichero de cabecera "stdarg.h", estas macros permiten manejar "fácilmente" las listas de argumentos desconocidos.

Tipos:

En el fichero de cabecera "stdarg.h" de define un tipo: va_list.

Será necesario declarar una variable de este tipo para tener acceso a la lista de parámetros.

Macros:

También se definen tres macros: va_start, va_arg y va_end.

void va_start(va_list ap, ultimo);

Ajusta el valor de "ap" para que apunte al primer parámetro de la lista. <ultimo> es el identificador del último parámetro fijo antes de comenzar la lista.

tipo va_arg(va_list ap, tipo);

Devuelve el siguiente valor de la lista de parámetros, "ap" debe ser la misma variable que se actualizó previamente con "va_start", "tipo" es el tipo del parámetro que se tomará de la lista.

void va_end(va_list va);

Permite a la función retornar normalmente, restaurando el estado de la pila, esto es necesario porque algunas de las macros anteriores pueden modificarla, haciendo que el programa termine anormalmente.

Uso de las macros para leer la lista de parámetros:

<tipo>funcion(<tipo> <id1> [, <tipo> <id2>...], ...) 
{ 
   va_list ar; // Declarar una variable para manejar la lista
 
   va_start(ar, <idn>); // <idn> debe ser el nombre del último parámetro antes de ... 
   <tipo> <arg>; // <arg> es una variable para recoger un parámetro 
   while((<arg> = va_arg(ar, <tipo>)) != 0) {// <tipo> debe ser el mismo que es de <arg> 
      // Manejar <arg> 
   }
   va_end(ar); // Normalizar la pila
}

Hay que usar un sistema que permita determinar cúal es el último valor de la lista de parámetros.

Una forma que el último valor de la lista de parámetros en la llamada a la función sea un 0, (o más en general, un valor conocido).

También puede hacerse que uno de los parámetros conocidos sea la cuenta de los parámetros desconocidos.

Además es necesario que el programador conozca el tipo de cada parámetro, para así poder leerlos adecuadamente, lo normal es que todos los parámetros sean del mismo tipo, o que se use un mecanismo como la de "printf", donde analizando el primer parámetro se pueden deducir el tipo de todos los demás. Este último sistema también sirve para saber el número de parámetros.

Ejemplos:

#include <iostream.h> 
#include <stdarg.h>
 
void funcion(int a, ...);
 
int main() { 
   funcion(1, "cadena 1", 0); 
   funcion(1, "cadena 1", "cadena 2", "cadena 3", 0); 
   funcion(1, 0); 
   return 0; 
}
 
void funcion(int a, ...) { 
   va_list p; 
   va_start(p, a); 
   char *arg;
 
   while ((arg = va_arg(p, char*))) { 
      cout << arg << " "; 
   } 
   va_end(p); 
   cout << endl; 
} 

Otro Ejemplo, este usando un sistema análogo al de "printf":

#include <iostream.h> 
#include <string.h> 
#include <stdarg.h>
 
void funcion(char *formato, ...);
 
int main() { 
   funcion("ciic", "Hola", 12, 34, "Adios"); 
   funcion("ccci", "Uno", "Dos", "Tres", 4); 
   funcion("i", 1); 
   return 0; 
}
 
void funcion(char *formato, ...) 
{
   va_list p; 
   char *szarg; 
   int iarg; 
   int i;
 
   va_start(p, formato); 
   /* analizamos la cadena de formato para saber el número y tipo de los parámetros*/ 
   for(i = 0; i < strlen(formato); i++) 
   { 
      switch(formato[i]) { 
         case 'c': /* Cadena de caracteres */ 
            szarg = va_arg(p, char*); 
            cout << szarg << " "; 
            break; 
         case 'i': /* Entero */ 
            iarg = va_arg(p, int); 
            cout << iarg << " "; 
            break; 
      } 
   } 
   va_end(p); 
   cout << endl; 
} 

pagina021 Principal pagina022b