Funciones en C++¶
Básicamente una función puede realizar las mismas acciones que un programa:
aceptar datos
realizar unos cálculos determinados y, finalmente,
devolver resultados
Las funciones son invocadas desde otras funciones, con una excepción:
la función global main()
, que tienen todos los programas en C++.
Permite al compilador conocer donde está el punto inicial de un
programa. Por razones obvias, main()
no puede ser invocada desde otras
funciones.
Podemos distinguir 3 características de las funciones en C++:
la definición
la declaración
la llamada
Definición de una función¶
Es el código que realiza las tareas para las que la función ha sido prevista.
La primera línea de la definición recibe el nombre de encabezamiento y el resto, un bloque encerrado entre llaves, es el cuerpo de la función.
La definición de una función se debe realizar en alguno de los ficheros que forman parte del programa.
La sintaxis habitual de una definición de función es la siguiente
tipo nombre_funcion(tipo_1 arg_1, ..., tipo_n arg_n)
{
sentencias;
return expresion; // optativo
}
tipo
: indica el tipo de valor (int
,float
, etc.) devuelto por la función.nombre_funcion
: es el identificador usado para la función.la lista de argumentos es una secuencia de declaración de parámetros separados por comas y encerrados entre paréntesis. Son los llamados parámetros formales de la función.
return expresion
es un salto incondicional que permite evaluar una expresión y devolver su valor a la función llamante.
Veamos un ejemplo de definición de función que calcula la media de dos números reales.
Ejemplo
double calcula_media(double num1, double num2)
{
double media;
media = (num1 + num2)/2.;
return media;
}
El tipo de una función¶
Una función devuelve, como mucho, un único valor a través de la
sentencia return
. Este valor tendrá el mismo tipo que el
de la función.
La palabra reservada return
permite realizar un
salto incondicional, de la misma forma que break
. En este caso, devuelve desde el interior de la función actual
el control del programa a la función que la llamó.
Una función puede tener varios puntos en los que se devuelve un valor con
return
y, lógicamente, finalizará en el primero que se ejecute.
Al igual que con los break
, la legibilidad del código debe ser la
decisión que determine que haya un único return
(preferible) o varios.
Declaración de una función¶
Al igual que ocurre con otros identificadores, en C++ no podemos llamar a una función en una sentencia sin que esté declarada previamente.
Una declaración explícita de una función, también denominada prototipo de la función, tiene la expresión general:
tipo nombre_funcion(tipo_1, tipo_2, ..., tipo_n);
En el ejemplo anterior el prototipo de la función es:
double calcula_media(double, double);
Es habitual encontrar prototipos acompañados de identificadores, en aras a mejorar la legibilidad del código. En cualquier caso es opcional. Así, el ejemplo anterior podría programarse como:
double calcula_media(double x, double y);
Recordemos que en C++, una declaración permite al compilador:
conocer de antemano las necesidades de memoria
(se enviarán a la función dos
double
y se recibirá undouble
)gracias al tipado estático, detectar errores en tiempo de compilación
por ejemplo, si utilizamos la función con argumentos cuyos tipos no son compatibles con los explicitados en su prototipo.
LLamada a la función¶
La llamada a una función se hace especificando su nombre y, entre paréntesis, las expresiones cuyos valores se van a enviar como argumentos de la función.
Estos parámetros pueden ser identificadores o cualquier otra expresión válida.
La llamada a una función se escribe de forma general como sigue:
salida = nombre_funcion(arg_1, arg_2, ..., arg_n);
En nuestro ejemplo podría ser:
double resultado = calcula_media(numero1, numero2);
o, por ejemplo:
double resultado = calcula_media(numero1+numero2, 7);
Veamos un ejemplo completo con la función calcula_media()
Ejemplo
// Cálculo de la media de dos números
#include <iostream>
using namespace std;
double calcula_media(double, double); // Declaración
int main()
{
double numero1, numero2;
cout << "Introduzca el primer número: ";
cin >> numero1;
cout << "Introduzca el segundo número: ";
cin >> numero2;
double resultado = calcula_media(numero1, numero2); // Llamada
cout << "La media de "<< numero1 << " y " << numero2
<< " es " << resultado << ".\n";
}
// Definición
double calcula_media(double num1, double num2)
{
double media;
media = (num1+num2)/2.;
return media;
}
Error debido a una función no declarada¶
Es muy importante entender las consecuencias derivadas de:
no declarar una función
no definir una función
En el ejemplo, comente la línea de la declaración de la función:
// double calcula_media(double, double); // Declaración
Al compilar el programa, obtendrá un error similar a:
error: use of undeclared identifier 'calcula_media'
o
error: 'calcula_media' was not declared in this scope
La razón es obvia. Todo identificador debe estar declarado antes de su uso. Cuando el compilador analiza la línea:
double resultado = calcula_media(numero1, numero2);
desconoce qué tipo de identificador es calcula_media
.
Error debido a una función no definida¶
En el ejemplo, comente toda la definición de la función.
//double calcula_media(double num1, double num2)
//{
// double media;
// media = (num1 + num2)/2.;
// return (media); // return media es válido también
//}
Al compilar el programa, obtendrá un error similar a:
undefined reference to `calcula_media(double, double)'
,error: linker command failed with exit code 1
Claramente aparece el aviso de que no está definida la función,
undefined
. En realidad, el compilador ha sido capaz de generar el
código objeto del archivo. Toda la información necesaria está
disponible respecto a la función main()
.
Es el enlazador (linker) el que ha dado la voz de alarma. No encuentra un archivo donde esté la definición de la función.
Declaración y definición simultáneas¶
Al igual que con las variables de tipos fundamentales, podemos optar por declarar y definir en un mismo paso, como puede verse en el ejemplo siguiente.
// Cálculo de la media de dos números
#include <iostream>
using namespace std;
// Declaración y definición simultáneas
double calcula_media(double num1, double num2)
{
double media;
media = (num1+num2)/2.;
return (media); // return media es también válido;
}
int main()
{
double numero1, numero2;
cout << "Introduzca el primer número: ";
cin >> numero1;
cout << "Introduzca el segundo número: ";
cin >> numero2;
double resultado = calcula_media(numero1, numero2); // Llamada
cout << "La media de "<< numero1 << " y " << numero2
<< " es " << resultado << ".\n";
}
Funciones void
¶
En ocasiones una función no necesita devolver ningún valor y, por tanto,
no es obligatorio usar return
.
Para ello, debemos definir la función con un tipo especial llamado void
.
Ejemplo
#include <iostream>
using namespace std;
void imprime_cadena(string cadena)
{
cout << cadena;
// return; // Opcional
}
int main()
{
string cadena = "Hola";
imprime_cadena(cadena);
imprime_cadena(" mundo.\n");
}
Edita, compila y ejecuta el código
Nota
std::string
es un tipo de dato no nativo del espacio de nombres
std
, que permite almacenar y manipular cadenas de caracteres.
Funciones sin argumentos¶
Una función puede no necesitar una lista de parámetros.
Ejemplo
#include <iostream>
using namespace std;
//Opcional void imprime_mensaje_inicial(void)
void imprime_mensaje_inicial()
{
cout << "Este programa bla bla bla…\n";
}
int main()
{
imprime_mensaje_inicial();
}