2.09 · Funciones: Definición, Parámetros y Retorno
🎯 Objetivo de aprendizaje
Al terminar este tema vas a poder:
- Definir funciones en C++ con tipo de retorno, nombre, parámetros y cuerpo.
- Llamar funciones desde main y desde otras funciones.
- Pasar argumentos por valor a las funciones.
- Devolver valores con return desde una función.
- Aplicar el principio "una función, una responsabilidad".
- Escribir prototipos (declaraciones anticipadas) de funciones.
- Usar parámetros por defecto para hacer funciones más flexibles.
Las funciones son los "ladrillos" de un programa. Con ellas, divides un problema grande en problemas pequeños, cada uno resuelto por una función. Esto hace tu código legible, testeable y reutilizable.
🧠 Teoría y conceptos — 2.9.1 — El problema: programas monolíticos

Qué es un programa monolítico
Un programa monolítico es aquel que tiene toda la lógica en main (o en un solo bloque). Ya escribiste varios. Funcionan, pero son difíciles de:
- Leer: un main de 200 líneas abruma.
- Testear: no puedes probar pedazos por separado.
- Reutilizar: la lógica está atada al programa específico.
- Mantener: un cambio en una parte puede romper otras.
La solución: funciones
Una función es un bloque de código con nombre que:
- Hace una sola cosa bien hecha.
- Puede recibir datos de entrada (parámetros).
- Puede devolver un resultado (valor de retorno).
- Se puede llamar desde cualquier parte del programa.
toma un programa tuyo del LAB anterior que tenga más de 50 líneas en `main`. Identifica 3 bloques de lógica que podrían ser funciones separadas.
2.9.2 — Anatomía de una función

Sintaxis en C++
tipoRetorno nombreFuncion(tipo1 param1, tipo2 param2, ...) {
// cuerpo de la función
// ...
return valor; // Si la función no es void
}
Las 4 partes
Ejemplo: función que suma dos números
int sumar(int a, int b) { // tipo=int, nombre=sumar, params=(a, b)
int resultado = a + b; // cuerpo
return resultado; // retorno
}
Funciones void: no devuelven nada
Si una función solo hace algo pero no devuelve un valor, usa void como tipo de retorno y omite el return (o usa return; sin valor).
void saludar(string nombre) {
cout << "¡Hola, " << nombre << "!" << endl;
// No hay return (void)
}
la sintaxis de función. Memorízala: `tipo nombre(parámetros) { cuerpo }`.
2.9.3 — Definir y llamar funciones

El flujo
- Definir la función (escribirla).
- Llamar la función desde main u otra función.
- La función ejecuta su cuerpo y (si aplica) devuelve un valor.
Ejemplo completo
#include <iostream>
#include <string>
using namespace std;
// Definición de la función
int sumar(int a, int b) {
return a + b;
}
int main() {
int x = 5, y = 3;
int resultado = sumar(x, y); // Llamada a la función
cout << "Suma: " << resultado << endl; // 8
return 0;
}
Diagrama de flujo de la llamada a función
┌─────────────┐
│ INICIO │ ⬭
└──────┬──────┘
│
▼
╱─────────────╲
║ x = 5, y = 3 ║ ▭
╚════════╤══════╝
│
▼
┌──────────────────┐
│ LLAMAR sumar(x,y)│ ─────┐
└─────────┬────────┘ │
│ │
▼ │
┌─────────────┐ │
│ INICIO │ ⬭ │
└──────┬──────┘ │
│ │
▼ │
╔═════════════╗ │
║ a = 5, b = 3 ║ ▭ │
║ return a + b ║ │
╚══════╤══════╝ │
│ │
▼ │
┌─────────────┐ │
│ FIN │ ⬭ │
└──────┬──────┘ │
│ │
└───► 8 ────────►│
│
▼
╔══════════════╗
║ resultado = 8 ║ ▭
╚══════╤═══════╝
│
▼
┌─────────────┐
│ FIN │ ⬭
└─────────────┘
Lo que muestra el diagrama: la llamada a función es una "subrutina" en el flujo. El control pasa a la función, ejecuta su cuerpo, y devuelve un valor al punto de llamada.
Llamadas anidadas
Una función puede llamar a otra función:
int duplicar(int x) { return x * 2; }
int sumar(int a, int b) { return a + b; }
int main() {
int resultado = sumar(duplicar(3), duplicar(5)); // sumar(6, 10) = 16
cout << resultado << endl;
return 0;
}
Traza: duplicar(3) = 6, duplicar(5) = 10, sumar(6, 10) = 16.
Una función, una responsabilidad
// ❌ MAL: la función hace 3 cosas
void procesarEstudiante(string nombre, double calificaciones[], int n) {
// 1. Validar
if (nombre == "") { cout << "Inválido"; return; }
// 2. Calcular promedio
double suma = 0;
for (int i = 0; i < n; i++) suma += calificaciones[i];
double promedio = suma / n;
// 3. Imprimir
cout << nombre << ": " << promedio << endl;
}
// ✅ BIEN: 3 funciones, cada una hace 1 cosa
bool esNombreValido(string nombre) { return !nombre.empty(); }
double calcularPromedio(double calificaciones[], int n) {
double suma = 0;
for (int i = 0; i < n; i++) suma += calificaciones[i];
return suma / n;
}
void imprimirReporte(string nombre, double promedio) {
cout << nombre << ": " << promedio << endl;
}
la regla de "una función, una responsabilidad". Memorízala.
2.9.4 — Parámetros: cómo recibir datos

Paso por valor (por copia)
En C++ por defecto, los argumentos se pasan por valor: la función recibe una COPIA del valor original. Modificar el parámetro NO afecta a la variable original.
void incrementar(int x) {
x++; // Solo modifica la copia local
}
int main() {
int n = 5;
incrementar(n);
cout << n; // 5, NO 6
}
Múltiples parámetros
double calcularIMC(double peso, double estatura) {
assert(estatura > 0);
return peso / (estatura * estatura);
}
0 parámetros
int obtenerNumeroAleatorio() {
return rand() % 100; // número entre 0 y 99
}
Parámetros con valores por defecto
void saludar(string nombre, string saludo = "Hola") {
cout << saludo << ", " << nombre << endl;
}
int main() {
saludar("Ana"); // "Hola, Ana"
saludar("Ana", "Buenos días"); // "Buenos días, Ana"
}
los 4 tipos de funciones según parámetros (sin parámetros, 1, varios, con defaults). Da un ejemplo de cada uno.
2.9.5 — Valor de retorno: cómo devolver datos

return termina la función
int dividir(int a, int b) {
if (b == 0) {
return -1; // Termina inmediatamente con -1
}
return a / b;
}
Múltiples return (en diferentes caminos)
string clasificarEdad(int edad) {
if (edad < 0) return "Inválida";
if (edad < 12) return "Niño";
if (edad < 18) return "Adolescente";
if (edad < 65) return "Adulto";
return "Adulto mayor"; // Si ninguna anterior se cumplió
}
Función void: sin retorno
void saludar() {
cout << "¡Hola!" << endl;
// No hay return
}
void despedirse() {
cout << "¡Adiós!" << endl;
return; // Opcional en void
}
Función que retorna un booleano
Patrón muy común para validaciones:
bool esValido(int edad) {
return edad >= 0 && edad <= 150;
}
// Uso:
if (esValido(edad)) {
cout << "Edad válida" << endl;
} else {
cout << "Edad inválida" << endl;
}
2.9.6 — Prototipos: declarar antes de usar

El problema
En C++, si llamas a una función antes de definirla, el compilador no sabe qué hace y da error.
// ❌ ERROR: el compilador no conoce "saludar" en main
int main() {
saludar("Ana");
}
void saludar(string nombre) { // Definición después de la llamada
cout << "Hola " << nombre << endl;
}
La solución: prototipos
Un prototipo (o declaración) le dice al compilador "esta función existe, sus parámetros son estos, y devuelve este tipo". Puede ir ANTES de la definición.
// Prototipo
int sumar(int a, int b);
int main() {
cout << sumar(3, 5); // ✅ Ahora el compilador sabe qué es
return 0;
}
// Definición
int sumar(int a, int b) {
return a + b;
}
Archivos de cabecera (avanzado)
En proyectos grandes, los prototipos van en archivos .h (header) y las definiciones en archivos .cpp. Veremos esto en detalle en el Tema 2.10.
cuándo y cómo usar prototipos. Memorízalo: en programas con varias funciones, los prototipos van al inicio.
2.9.7 — Parámetros por defecto
Declaración
double calcularPrecio(double precioBase, double iva = 0.16, double descuento = 0) {
return precioBase * (1 + iva) * (1 - descuento);
}
int main() {
cout << calcularPrecio(1000); // 1000 * 1.16 = 1160
cout << calcularPrecio(1000, 0.10); // 1000 * 1.10 = 1100
cout << calcularPrecio(1000, 0.16, 0.20); // 1000 * 1.16 * 0.80 = 928
}
Reglas
- Los parámetros con default van al final de la lista.
- Si un parámetro tiene default, todos los siguientes también deben tener default.
las reglas de los parámetros por defecto. Da un ejemplo propio.
2.9.8 — Alcance de variables (introducción)
Variables locales
Las variables declaradas dentro de una función existen solo dentro de esa función.
void miFuncion() {
int x = 5; // x existe solo aquí
cout << x; // OK
}
int main() {
miFuncion();
cout << x; // ❌ ERROR: x no existe aquí
}
Variables globales
Las variables declaradas fuera de cualquier función existen en todo el programa.
int contadorGlobal = 0; // Variable global
void incrementar() {
contadorGlobal++;
}
int main() {
incrementar();
cout << contadorGlobal; // 1
return 0;
}
Variables locales con el mismo nombre
int x = 10; // Global
void miFuncion() {
int x = 5; // Local, OCULTA a la global
cout << x; // 5 (la local)
}
int main() {
cout << x; // 10 (la global)
miFuncion();
return 0;
}
Regla: usa variables locales siempre que puedas. Las globales son propensas a errores porque cualquier función puede modificarlas.
la diferencia entre local y global. Da un ejemplo de cuándo usar cada una.
🤖 IA como copiloto — 🤖 AI Mission 2.9
Prompt 1: "Te voy a pegar un main largo. NO me lo corrijas. Solo dime: (1) qué bloques de código podrían ser funciones separadas, (2) qué nombres descriptivos les pondrías. Máximo 150 palabras."
Prompt 2: "Necesito una función en C++ que calcule el área de un círculo. Usa el patrón: nombre descriptivo, parámetro por valor, tipo de retorno double, assert en el cuerpo. Dame el código y explícame cada parte. No me corrijas nada. Máximo 200 palabras."
🧪 Laboratorio — 🧪 LAB 2.9 — 8 ejercicios de funciones
🛠️ Herramienta recomendada para los diagramas de flujo de este LAB: Para los ejercicios que pidan un diagrama de flujo, usa [draw.io (diagrams.net)](https://app.diagrams.net/) — herramienta gratis, sin registro, que funciona en el navegador. Tiene plantillas con la simbología ANSI/ISO lista (en `General → Flowchart`). Exporta tus diagramas como PNG e insértalos en tu cuaderno digital o entrégalos junto con el código.
Ejercicio 1 — Función "saludar" (básico, 10 min)
Enunciado. Crea una función void saludar(string nombre) que imprima "¡Hola, [nombre]!". Llámala desde main con 3 nombres diferentes.
Rúbrica (10 pts): función (4 pts) + 3 llamadas (3 pts) + compilación (3 pts).
Ejercicio 2 — Función "esPar" (básico, 15 min)
Enunciado. Crea una función bool esPar(int n) que devuelva true si n es par. Escribe 5 tests con assert (cubre normal, borde, negativo).
Rúbrica (10 pts): función (4 pts) + 5 tests (4 pts) + compilación (2 pts).
Ejercicio 3 — Función "mayor de 3" (básico, 20 min)
Enunciado. Crea una función int mayorDeTres(int a, int b, int c) que devuelva el mayor de 3 números. Sin usar arreglos ni funciones auxiliares (hazlo con if-else anidados o encadenados).
Rúbrica (10 pts): función (5 pts) + 5 tests (5 pts).
Ejercicio 4 — Función "factorial" (intermedio, 25 min)
Enunciado. Crea una función recursiva o iterativa int factorial(int n) que calcule n!. Maneja n=0 (devuelve 1) y n<0 (assert falla o mensaje de error).
Rúbrica (10 pts): función (5 pts) + casos borde (3 pts) + tests (2 pts).
Ejercicio 5 — Función "esPrimo" (intermedio, 25 min)
Enunciado. Crea bool esPrimo(int n). Un primo solo es divisible entre 1 y sí mismo. Escribe 5 tests.
Rúbrica (10 pts): algoritmo (5 pts) + 5 tests (5 pts).
Ejercicio 6 — Función con menú (avanzado, 30 min)
Enunciado. Construye un menú con 3 opciones (calcular área, perímetro, salir) usando do-while + switch + funciones. Cada opción llama a una función diferente.
Rúbrica (10 pts): 3 funciones (5 pts) + menú (3 pts) + repetición (2 pts).
Ejercicio 7 — Refactor de programa monolítico (avanzado, 30 min)
Enunciado. Toma el programa de "Calculadora de Calificaciones" del Boss 1. Refactorízalo para que main solo llame a funciones (no tenga lógica). Cada función hace una sola cosa.
Rúbrica (10 pts): 5+ funciones (5 pts) + main limpio (3 pts) + comportamiento idéntico (2 pts).
Ejercicio bonus — Calculadora científica (opcional, 30 min)
Enunciado. Crea una calculadora científica con funciones para: sumar, restar, multiplicar, dividir, potencia, raíz cuadrada, seno, coseno, logaritmo. Usa <cmath>.
Rúbrica bonus (5 pts): 6+ funciones matemáticas (3 pts) + menú (1 pt) + tests (1 pt).
🎯 Cierre del tema
Lo que aprendiste hoy:
- La anatomía completa de una función: tipo, nombre, parámetros, cuerpo.
- Cómo definir y llamar funciones.
- Paso por valor (por copia) y cómo afecta a las variables originales.
- Tipos de retorno (int, double, string, bool, void).
- Prototipos para llamar funciones antes de definirlas.
- Parámetros por defecto.
- Variables locales vs globales.
- La regla "una función, una responsabilidad".
Lo que sigue: en el Tema 2.10 — Modularidad: Scope, Paso por Valor/Referencia, Multi-archivo (8h), vas a profundizar en cómo las funciones interactúan entre sí: cómo se comunican con valores, cómo se comparten datos, y cómo organizar un programa en múltiples archivos .cpp y .h. Es la base de los proyectos profesionales.
XP obtenida al completar este tema: 100 base + 30 por LAB (8 ejercicios) + 20 por Quest = 150 XP.
*"Un programa sin funciones es un muro de ladrillos pegados con la lengua. Un programa con funciones es un edificio con columnas."* — De la introducción de este manual.
Fin del Tema 2.9
📝 Quest · Cuestionario — 📝 Quest — Reactivos para autoevaluación
Las siguientes preguntas te sirven para autoevaluarte después de leer el tema. Responde en tu cuaderno o mentalmente, y luego revisa las Respuestas modelo (disponibles en libre acceso, sin iniciar sesión).
Sección A · Opción múltiple
Elige la opción correcta (A, B, C o D). Las respuestas están en la sección Respuestas modelo.
- ¿Qué es una función en C++?
- Un tipo de variable
- Un bloque de código reutilizable con nombre
- Un bucle
- Un comentario
- Sintaxis de declaración de función:
- function nombre()
- tipo_retorno nombre(params) { cuerpo }
- def nombre():
- func nombre() {}
- ¿Qué significa void en una función?
- Variable vacía
- La función no retorna valor
- Función sin parámetros
- Función privada
- return en una función void:
- Obligatorio
- Opcional, pero sale de la función
- Prohibido
- Hace nada
- ¿Cómo se llama una función en C++?
- call nombre()
- nombre();
- invoke nombre
- do nombre()
- Parámetros por valor:
- Modifican el original
- Reciben una copia, no afectan al original
- Comparten memoria
- Son referencias
- Parámetros por referencia (&):
- Copia
- Operan sobre la variable original
- Son constantes
- No existen
- Sobrecarga de funciones:
- Funciones con el mismo nombre y misma firma
- Funciones con el mismo nombre pero diferentes parámetros
- Funciones sin nombre
- Funciones globales
- Recursividad:
- Bucle
- Función que se llama a sí misma
- Variable estática
- Compilador
- ¿Por qué las funciones deben ser pequeñas?
- Compilan más rápido
- Más fáciles de leer, testear y mantener
- Caben en pantalla
- No es importante
Sección B · Preguntas abiertas
Desarrolla tu respuesta en al menos 3 líneas. Compara con la respuesta modelo después de escribir.
- ¿Por qué es importante que las funciones tengan una sola responsabilidad?→ Escribe tu respuesta aquí (en tu cuaderno o mentalmente)…
- Diseña una función "calcularPromedio(vector<int> notas)" en C++ pseudocódigo.→ Escribe tu respuesta aquí (en tu cuaderno o mentalmente)…
- Explica la diferencia entre parámetro por valor, por referencia y por puntero. ¿Cuándo usar cada uno?→ Escribe tu respuesta aquí (en tu cuaderno o mentalmente)…
🟢 Cuando termines, revisa las Respuestas modelo y compáralas con las tuyas. La mejor forma de aprender es discutir cada respuesta contigo mismo o con un compañero.