Sobrecarga y sobrescritura. Dos conceptos cuyos nombres se parecen tanto que uno se pregunta por qué tenían que ser así.
Son temas habituales en exámenes y entrevistas, y sus nombres similares son gran parte del motivo de la confusión. En realidad, sus mecanismos son completamente distintos: uno crea varias funciones con el mismo nombre y el otro redefine una función heredada.
También se determinan en momentos distintos: una en tiempo de compilación y la otra en tiempo de ejecución. Esta diferencia da pie a hablar de despacho estático y despacho dinámico en términos de rendimiento.
En este artículo los diferenciaremos claramente con ejemplos de Swift.
Este es el resumen clave.
- Sobrecarga: Definir varias funciones con el mismo nombre y parámetros distintos. No depende de la herencia
- Sobrescritura: El hijo redefine el método del padre. Requiere herencia
- La sobrecarga decide la función en tiempo de compilación; la sobrescritura, en tiempo de ejecución
- La sobrescritura es el mecanismo central del polimorfismo
Sobrecarga: varias funciones con el mismo nombre
La sobrecarga consiste en definir varias funciones con el mismo nombre, pero distinta configuración de parámetros: cantidad, tipos o etiquetas.
func area(radius: Double) -> Double { .pi * radius * radius }
func area(width: Double, height: Double) -> Double { width * height }
func area(side: Double) -> Double { side * side }
El compilador determina la función a partir de los argumentos enviados en la llamada. En cuanto escribes area(radius: 3), queda seleccionada la primera función. Se decide antes de ejecutar.
Piensa en C, que no tenía sobrecarga, y entenderás su utilidad. La función de valor absoluto tenía nombres distintos según el tipo: abs, labs y fabs. La sobrecarga permite que los conceptos iguales tengan el mismo nombre.
Swift usa sobrecarga por toda su biblioteca estándar, en funciones como print(:) y min(:_:). La sobrecarga de operadores también permite que un único + gestione sumas de enteros, concatenación de cadenas y combinación de arrays.
Una advertencia: conviene evitar sobrecargas que solo difieran en el tipo de retorno. Swift lo permite sintácticamente en algunos casos, pero sin especificar el tipo en la llamada aparece un error de ambigüedad y el código resulta confuso.
Sobrescritura: redefinir lo heredado
La sobrescritura consiste en que una clase hija redefine, con la misma firma, un método heredado de la clase padre. La relación de herencia es un requisito.
class Animal {
func speak() { print("...") }
}
class Dog: Animal {
override func speak() { print("Guau") }
}
class Cat: Animal {
override func speak() { print("Miau") }
}
Este es el momento clave.
let animals: [Animal] = [Dog(), Cat()]
for animal in animals {
animal.speak() // Guau, miau
}
El tipo de la variable es Animal, pero se ejecuta el método de la instancia real. Qué speak se invoca se decide en tiempo de ejecución observando el objeto real. Eso es el despacho dinámico, el mecanismo que hace funcionar el polimorfismo.
También merece atención que Swift obligue a usar la palabra clave override. El compilador detecta si creas por error un método con la misma firma que el del padre o si fallas al sobrescribir por un error tipográfico. Por el contrario, añadir final en el padre permite prohibir la sobrescritura.
Comparación rápida en una tabla
| Categoría | Sobrecarga | Sobrescritura |
|---|---|---|
| Definición | Mismo nombre, parámetros distintos | Redefinir la misma firma |
| Herencia | No necesaria | Obligatoria |
| Momento de decisión | Tiempo de compilación (estático) | Tiempo de ejecución (dinámico) |
| Objetivo | Coherencia de nombres, comodidad de la API | Polimorfismo, sustitución del comportamiento |
| Palabra clave de Swift | Ninguna | override (obligatoria); se prohíbe con final |
La diferencia en el momento de decisión también afecta al rendimiento. Una llamada resuelta en compilación (despacho estático) puede saltar directamente, mientras que una decisión en ejecución (despacho dinámico) debe pasar por la tabla de métodos del tipo real. En Swift, marcar algo como final o private permite que el compilador convierta el despacho dinámico en estático y lo optimice.
Un truco para no confundirlas
Recuerda el significado literal de las palabras inglesas.
Overload = sobrecargar. Es como “cargar” varias funciones sobre el mismo nombre. Un nombre, varias funciones.
Override = ignorar y pasar por encima. Es “sobrescribir” la definición del padre. Una definición, contenido reemplazado.
Una respuesta de entrevista puede empezar así.
«La sobrecarga consiste en tener varias funciones con el mismo nombre y distintos parámetros, y se decide en tiempo de compilación. La sobrescritura redefine un método heredado y se decide en tiempo de ejecución según el tipo real. La que crea polimorfismo es la sobrescritura.»
Resumen
- Sobrecarga: definir varias funciones con el mismo nombre y distinta configuración de parámetros. No requiere herencia
- Sobrescritura: el hijo redefine el método del padre con la misma firma. Requiere herencia
- La sobrecarga determina el destino de la llamada en compilación (estático); la sobrescritura, en ejecución (dinámico)
- El mecanismo central del polimorfismo es la sobrescritura y el despacho dinámico
- Swift evita errores al exigir la palabra clave override, y final puede prohibir la sobrescritura
- Truco: Overload sobrecarga un nombre; Override sobrescribe una definición

