Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Una función es un conjunto de líneas de código que realizan una tarea específica y
puede retornar un valor. Las funciones pueden tomar parámetros que modifiquen su
funcionamiento. Las funciones son utilizadas para descomponer grandes problemas en
tareas simples y para implementar operaciones que son comúnmente utilizadas durante
un programa y de esta manera reducir la cantidad de código. Cuando una función es
invocada se le pasa el control a la misma, una vez que esta finalizó con su tarea el
control es devuelto al punto desde el cual la función fue llamada.
Nota: aunque para la función que veremos el tipo de retorno coincide con el tipo de
parámetro pasado, algunas veces las cosas pueden cambiar, es decir, no es obligatorio
que una función reciba un parámetro de un tipo y que tenga que regresar una respuesta
de dicho tipo.
Para mostrar un ejemplo del paso de parámetros por referencia, vamos a retomar el caso
de la función cuadrado, salvo que en esta ocasión cambiaremos ligeramente la sintaxis
para definir la misma. Veamos:
Notas: se debe de aclarar que el uso de la palabra void dentro de los parentesis es
opcional al momento de declarar una función. Asi, la función pausa() podría haberse
declarado como void pausa(), y la misma puede invocarse como: pausa();.
Funciones anidadas
A diferencia de Pascal, el lenguaje C,C++ no permite anidar funciones, sin embargo,
dentro de una funcíon puede existir la llamada a una o más funciones declaradas
previamente.
Nota: observe que en la sintaxis para declarar funciones tipo puntero se debe de poner el
símbolo * despues del tipo y antes del nombre de la función que se está declarando.
Esto se puede ver en el programa, ya que la función binstr se declara como: char
*binstr(unsigned int);
// programa : funciones01.cpp
// autor : Wikipedia
#include <iostream.h>
#include <string.h>
// punto de prueba
int main()
{
int n = 128;
count << "decimal = " << n << ", binario = " << binstr(n) <<
endl;
cin.get();
}
strcpy(buffer, "0");
if (n > 0) {
while (n > 0) {
buffer[i] = ( n & 1 ) + '0';
i++;
n >>= 1;
}
buffer[i] = '\0';
strrev(buffer);
} // fin (n > 0)
return buffer;
}
Parámetros constantes
Los parámetros usados por una función pueden declararse como constantes ( const ) al
momento de la declaración de la función. Un parámetro que ha sido declarado como
constante significa que la función no podrá cambiar el valor del mismo ( sin importar si
dicho parámetro se recibe por valor o por referencia ).
Ejemplo:
int funcionX( const int n );
void printstr( const char *str );
Para ver un ejemplo más, vamos a considerar el caso de la función binstr() del
programa funciones01. Ahora, vamos modificar dicha función, salvo que esta ocasión
nos interesa que la misma sirva para convertir números decimales en cadenas numéricas
y cuya base de conversión sea pasada como parámetro. Es decir, la función de la que
estamos hablando podrá convertir números decimales a: binario, octal, decimal,
hexadecimal, etc.; y la única condición será que la base indicada esté entre el 2 y el 36,
inclusive.
// programa : funciones02.cpp
// autor : Oscar E. Palacios
#include <iostream.h>
#include <stdlib.h>
// declaración de prototipo
char *numstr(unsigned int, const int base = 10);
// punto de prueba
int main()
{
int n = 128;
count "decimal = " << n << ", binario = " << numstr(n, 2) <<
endl;
count "decimal = " << n << ", octal.. = " << numstr(n, 8) <<
endl;
cin.get();
}
Parámetros estructurados
Al igual que cualquier otro tipo los parámetros de tipo estruturado pueden pasarse por
valor o por referencia, sin embargo, podría ser que si una estructura es pasada por valor
el compilador mostrara una advertencia ( warning ) indicando que se pasado por valor
una estructura, puesto que el paso de estructuras por valor es permitido usted puede
ignorar la advertencia, pero lo mejor es pasar estructuras por referencia. Si una
estructura es pasada por valor y si esta es muy grande podria ser que se agotara la
memoria en el segmento de pila ( Stack Segment ), aparte de que la llamada a la función
sería más lenta.
struct empleado {
char nombre[32];
int edad;
char sexo; };
Ahora, pensemos que deseamos escribir una función para imprimir variables del tipo
empleado. Así, la función puede escribirse de las tres maneras siguientes:
Funciones sobrecargadas
C++, a diferencia del C estándar, permite declarar funciones con el mismo nombre y a
esto se conoce como sobrecarga de funciones. Las funciones sobrecargadas pueden
coincidir en tipo, pero al menos uno de sus parámetros tiene que ser diferente. En todo
caso, si usted trata de declarar funciones sobrecargadas que coincidan en tipo y número
de parámetros el compilador no se lo permitirá. Para poner un ejemplo vamos a
considerar el caso de dos funciones cuyo nombre será divide, ambas regresarán el
cociente de dos números, salvo que una de ellas operará sobre números enteros y la otra
lo hará sobre números reales ( de punto flotante ).
Nota: cuando en los programas se hace una llamada a una función sobrecargada, el
compilador determina a cual de las funciones invocar en base al tipo y número de
parámetros pasados a la función.
// programa : funciones03.cpp
// autor : Oscar E. Palacios
#include <iostream.h>
#include <stdlib.h>
// divide enteros
int divide(int a, int b)
{
cout << "división entera" << endl;
return ( (b != 0) ? a/b : 0);
}
// divide reales
double divide(double a, double b)
{
cout << "división real" << endl;
return ( (b != 0) ? a/b : 0);
}
// punto de prueba
int main()
{
cout << divide(10, 3) << endl;
cout << divide(10.0, 3.0) << endl;
cin.get();
}
Funciones recursivas
Una función recursiva es aquella que contiene una llamada a si misma. Usted
probablemente se pregunte ¿cúal es el objetivo de que una función se llame a si
misma ?. Bueno, déjeme decirle que habrá ocasiones en las cuales el uso de ésta técnica
tiene sus ventajas. Por ejemplo, las personas que manejan el lenguaje de las
matemáticas saben que hay ciertos procesos que son repetitivos, tal es el caso del
procedimiento para obtener el factorial de un número. Así, procederemos a escibir un
programa y dentro del mismo la función Factorial, misma que servirá como ejemplo de
una función recursiva. factorial tomará un solo parámetro tipo Long (entero largo)
pasado por valor y regresará el factorial del número.
r = 1;
if (n >1) {
for (p=1; p<=n; p++) r = r * p;
}
return r;
}
// punto de prueba
int main()
{
cout << "Demostración de una función recursiva" << endl << endl;
system("pause");
return 0;
}
La sintaxis que usaremos para declarar funciones con lista de parámetros variables es:
1) tipo nombrefuncion(...)
2) tipo nombrefuncion(int num, ...)
donde:
En el siguiente programa, por ejemplo, se define una función ( printstr ) que despliega
una lista variable de cadenas de caracteres.
// programa funciones05.cpp
// Autor: Oscar E. Palacios
#include <iostream.h>
#include <stdarg.h>
int main()
{
printstr("Hola, ", "Esta es\n", "una prueba\n", NULL);
cin.get();
return 0;
}
// programa funciones06.cpp
// Autor: Oscar E. Palacios
#include <iostream.h>
#include <stdarg.h>
va_end( argptr );
return( total );
}
int main()
{
cout << suma(4, 100, 200, 300, 400) << endl;
cin.get();
return 0;
}
Ahora bien, si usted pone a prueba la función Swap() verá que la misma funciona
perfectamente, salvo que tiene la limitante de operar solamente con números de tipo int.
Luego, si quisieramos intercambiar objetos de tipo double, float, char, etc. ¿ sera que
debemos repetir el mismo código para cada uno de los tipos deseados ?. La respuesta a
dicha interrogante es No, ya que la mayoría de compiladores actuales para C++
permiten el use de plantillas.
// programa funciones06.cpp
// Autor: Oscar E. Palacios
#include <iostream.h>
int main()
{
int i1 = 100;
int i2 = 5;
cout << "antes.. "<< "i1 = " << i1 << " i2 = " << i2 << endl;
SwapGenerico(i1, i2); // swap de números enteros
cout << "despues "<< "i1 = " << i1 << " i2 = " << i2 << endl;
cin.get();
return 0;
}
Otro problema
En el ejemplo anterior vimos que la plantilla SwapGenerico solucionó el problema de
intercambiar el contenido de una pareja de objetos primitivos ( char, int, float, double,
etc. ). Sin embargo, si usted pone a prueba la misma plantilla para hacer un Swap de
cadenas de caracteres, verá que el compilador le informará de un error, ya que a las
cadenas de caracteres no es posible aplicarles el operador de asignacíon (=). Pero, ya
que C++ lo permite, podemos escribir una función SwapGenerico sobrecargada y así el
compilador decidirá si usar la plantilla o usar la función de sobrecarga. Y de tal manera
abremos resuelto el problema. Así, puede agregar la siguiente función al programa visto
anteriormente.