Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Funciones
Funciones
Sintaxis
<tipo> [clase::] <nombre> ( [Parámetros] )
{
cuerpo;
}
Parámetros
Normalmente, las funciones operan sobre ciertos valores pasados a las mismas ya sea como constantes literales o
como variables, aunque se pueden definir funciones que no reciban parámetros. Existen dos formas en C++ de
pasar parámetros a una función; por referencia o por valor. El hecho es que si en una declaración de función se
declaran parámetros por referencia, a los mismos no se les podrá pasar valores literales ya que las referencias
apuntan a objetos (variables o funciones) residentes en la memoria; por otro lado, si un parámetro es declarado
para ser pasado por valor, el mismo puede pasarse como una constante literal o como una variable. Los
parámetros pasados por referencia pueden ser alterados por la función que los reciba, mientras que los
parámetros pasados por valor o copia no pueden ser alterados por la función que los recibe, es decir, la función
puede manipular a su antojo al parámetro, pero ningún cambio hecho sobre este se reflejará en el parámetro
original.
Parámetros por valor
La función cuadrado() (ver arriba) es un clásico ejemplo que muestra el paso de parámetros por valor, en ese
sentido la función cuadrado() recibe una copia del parámetro n. En la misma función se puede observar que se
realiza un cálculo ( n*n ), sin embargo el parámetro original no sufrirá cambio alguno, esto seguirá siendo cierto
aun cuando dentro de la función hubiera una instrucción parecida a n = n * n; o n*=n;.
Parámetros por referencia
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:
Al poner a prueba las funciones cuadrado() y cuadrado2() se podrá verificar que la primera de estas no cambia el
valor del parámetro original, mientras que la segunda sí lo hace.
Funciones void
Bajo ciertas circunstancias se deseará escribir funciones que no regresen valor alguno (esto sería algo parecido a
escribir procedures en Pascal) y para ello podemos declarar a la función como void. La palabra reservada void es
utilizada para declarar funciones sin valor de retorno y también para indicar que una función específica no requiere
de parámetros. Por ejemplo, la función pausa() que se verá en seguida, no devolverá valor alguno y la misma no
requiere de parámetros.
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);
#include <iostream>
#include <string.h>
// declaración de prototipo
char *binstr(unsigned int);
// punto de prueba
int main()
{
int n = 128;
cout << "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;
}
Variables estáticas y automáticas
Dentro de una función, las variables y/o constantes pueden ser declaradas como: auto (por omisión) o como static.
Si una variable dentro de una función es declarada como estática significa que la misma retendrá su valor entre las
llamadas a la función. Por otro lado, las variables automáticas pierden su valor entre las llamadas. En el programa
anterior puede verse que el arreglo de caracteres (buffer[65]) se ha declarado como estático para garantizar que
dicho buffer retenga los datos aún después de que la función termine. En el mismo ejemplo, si el buffer no se
declara como estático, el contenido del mismo podría ser destruido al salir de la función y los resultados obtenidos
podrían ser no deseados.
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.
Nota: Ya que la función servirá para convertir números a cualquier representación la nombraremos como numstr()
en lugar de binstr(). Si la función es invocada sin el parámetro base regresará una cadena de digitos decimales.
#include <iostream>
#include <stdlib.h>
// declaración de prototipo
char *numstr(unsigned int, const int base = 10);
// punto de prueba
int main()
{
int n = 128;
cout << "decimal = " << n << ", binario = " << numstr(n, 2) << endl;
cout << "decimal = " << n << ", octal.. = " << numstr(n, 8) << endl;
cin.get();
}
Anteriormente se mencionó que en C++ los parámetros a una función pueden pasarse por valor o por referencia, al
respecto, podemos agregar que los parámetros también pueden pasarse como punteros. El paso de parámetros de
punteros es bastante parecido al paso de parámetros por referencia, salvo que el proceso de los datos dentro de la
función es diferente. Por ejemplo, las funciones:
Ambas reciben un puntero o referencia a un objeto de tipo entero, por lo tanto cualquiera de las funciones del
ejemplo puede cambiar el valor de la variable entera apuntada por X, la diferencia radica en la forma en que cada
una de las mismas lleva cabo la tarea. Si en la función puntero() en lugar de usar *X = 100; se usara X = 100; se le
asignaría 100 al puntero X, más no al objeto apuntado por X, y esto podría ser la causa de que el programa se
terminara de manera abrupta.
Parámetros estructurados
Al igual que cualquier otro tipo los parámetros de tipo estructurado 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.
Para ver un ejemplo, consideremos el caso del siguiente tipo estructurado:
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.
#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();
}
donde:
1. tipo es el tipo regresado por la función
2. nombrefuncion es el nombre de la función
3. int num es el número de parámetros que la función procesará
4. ... esta notación se emplea para indicar que el número de parámetros es variable
Nota: observe que la primera forma de declaración es realmente variable el número de parámetros a procesar y en
estos casos se debe establecer el mecanismo para determinar cuándo se ha procesado el último de los
argumentos, en el segundo tipo de declaración el número total de parámetros a procesar es igual al valor del
parámetro num.
En el siguiente programa, por ejemplo, se define una función (printstr) que despliega una lista variable de cadenas
de caracteres.
#include <iostream.h>
#include <stdarg.h>
int main()
{
printstr("Hola, ", "Esta es\n", "una prueba\n", NULL);
cin.get();
return 0;
}
En el programa que se listará en seguida, se define la función suma(), misma que operará sobre listas de números
enteros, la función devolverá la suma de dichos números.
#include <iostream>
#include <stdarg.h>
va_end( argptr );
return( total );
}
int main()
{
cout << suma(4, 100, 200, 300, 400) << endl;
cin.get();
return 0;
}