Por qué existen las funciones
Una función es un bloque de código con nombre que puedes ejecutar cuando quieras llamándolo. En lugar de repetir la misma lógica en varios sitios, la escribes una sola vez, le das un nombre y llamas a ese nombre allí donde lo necesites. Esto hace que los programas sean más cortos, más fáciles de leer y más fáciles de corregir: cambias la lógica en un único lugar y todos los que la llaman reciben la actualización.
Ya llevas todo este tiempo llamando a una función: main. Es el punto de entrada desde el que arranca todo programa de C++. Ahora vas a escribir las tuyas propias. Los bucles que viste antes, como el for basado en rango, suelen vivir dentro de funciones para que puedas reutilizar toda una pieza de lógica por su nombre.
Anatomía de una función
Toda función tiene cuatro partes: un tipo de retorno, un nombre, una lista de parámetros entre paréntesis y un cuerpo entre llaves.
int add(int a, int b) { // tipo de retorno | nombre | parámetros
return a + b; // cuerpo
}
intes el tipo de retorno: la clase de valor que la función devuelve.addes el nombre que usas para llamarla.(int a, int b)son los parámetros: las entradas que proporciona el llamador.- Las llaves contienen el cuerpo, el código que se ejecuta cuando la llamas.
Aquí lo tienes en un programa completo. Definir la función encima de main significa que main puede verla cuando la llama.
La llamada add(2, 3) ejecuta la función con a = 2 y b = 3, y toda la expresión se convierte en el valor devuelto. Puedes guardarlo en una variable o usarlo directamente dentro de otra expresión, como hace la segunda línea de cout.
Devolver un valor
La sentencia return hace dos cosas: entrega un valor al llamador y termina la función de inmediato. Cualquier código que haya después de un return no se ejecuta: el control vuelve directamente al punto donde se llamó a la función.
El tipo del valor devuelto debe coincidir con el tipo de retorno declarado (o poder convertirse a él). Una función declarada como int debe devolver un int; no devolver nada, o salir por el final sin un return, es comportamiento indefinido en cualquier función que no sea void.
Funciones void
No todas las funciones producen un valor. Cuando una función solo hace algo (imprime una salida, actualiza el estado), su tipo de retorno es void. Una función void puede usar un simple return; para salir antes de tiempo, o sencillamente llegar hasta la llave de cierre.
Intentar usar el resultado de una función void (int x = greet("Ada");) es un error de compilación, porque no hay ningún valor que asignar. Un error frecuente es escribir return someValue; dentro de una función void; el compilador también lo rechaza.
Declaraciones frente a definiciones
C++ lee un archivo de arriba abajo, así que por defecto una función debe aparecer antes del código que la llama. Cuando ese orden resulta incómodo, divides la función en una declaración (también llamada prototipo) y una definición.
Una declaración indica la firma de la función y termina con un punto y coma, sin cuerpo. Le promete al compilador "esta función existe; así es como se llama". La definición completa puede venir después, incluso tras main.
Sin el prototipo de la línea 4, el compilador encontraría square(5) dentro de main antes de haber visto nunca square, y la compilación fallaría. Los prototipos son también la forma en que los archivos de cabecera permiten que muchos archivos fuente compartan las mismas funciones. Ten en cuenta que los nombres de los parámetros en una declaración son opcionales: int square(int); funciona igual de bien; al compilador solo le importan los tipos.
Errores comunes
Unas cuantas trampas atrapan a los principiantes una y otra vez:
- Llamar antes de declarar. Si obtienes un error "
addwas not declared in this scope", la función está definida por debajo de su primera llamada y no tiene prototipo. Sube la definición o añade un prototipo. - Olvidar el return. Llegar al final de una función que no es
voidsin unreturnes comportamiento indefinido: el llamador recibe basura. Compila con las advertencias activadas (-Wall) y el compilador lo señalará. - Confundir definir y llamar. Una definición tiene un cuerpo entre llaves y ningún punto y coma final. Una declaración tiene un punto y coma y ningún cuerpo. Mezclarlas (como poner un punto y coma justo después de la lista de parámetros de una función que querías definir) produce errores confusos.
- Ignorar el valor de retorno.
add(2, 3);en su propia línea compila, pero la suma calculada se descarta en silencio. Asegúrate de usar realmente lo que devuelve una función.
// Parece una definición, pero el ; perdido la convierte en una
// declaración seguida de un bloque sobrante, un error de escritura frecuente:
int triple(int n); // <- este ; termina la sentencia
{
return n * 3; // n no está definido aquí; este bloque queda huérfano
}
Siguiente: parámetros de función
Has visto que las funciones reciben entradas a través de su lista de parámetros, pero hay mucho más. La siguiente página profundiza en los parámetros de función: paso por valor frente a paso por referencia, argumentos por defecto, parámetros const y cómo esa elección afecta a si tu función puede cambiar los datos del llamador.
Preguntas frecuentes
¿Cómo se escribe una función en C++?
Dale un tipo de retorno, un nombre, paréntesis para los parámetros y un cuerpo entre llaves: int add(int a, int b) { return a + b; }. Llámala por su nombre con argumentos, como add(2, 3). Si la función no devuelve nada, usa void como tipo de retorno.
¿Cuál es la diferencia entre una declaración y una definición de función en C++?
Una declaración (o prototipo) le indica al compilador el nombre, el tipo de retorno y los parámetros de una función, y termina en punto y coma: int add(int a, int b);. Una definición además incluye el cuerpo entre llaves. Puedes declarar una función antes de main y definirla más tarde: la declaración te permite llamarla antes de que aparezca la definición.
¿Qué ocurre si una función de C++ no devuelve un valor?
En una función void, no pasa nada: simplemente termina. Pero en una función que no es void, llegar al final sin un return es comportamiento indefinido: el llamador recibe un valor basura y el programa puede comportarse mal. La mayoría de los compiladores avisan de esto; devuelve siempre un valor en cada camino de una función que no sea void.