HOWTO · C++
Sobrecarga de funciones y sobrescritura de funciones en C++
Compara la sobrecarga de funciones y la sobrescritura de funciones en C++, y explica cómo se seleccionan las funciones en cada caso.
En esta página
La sobrecarga y la sobrescritura de funciones resuelven problemas distintos en C++. La sobrecarga de funciones permite que varias funciones del mismo ámbito tengan el mismo nombre y listas de parámetros diferentes; el compilador elige una según los argumentos de la llamada. La sobrescritura de funciones permite que una clase derivada reemplace una función virtual heredada con una implementación compatible; cuando la llamada se hace mediante una referencia o un puntero a la clase base, el despacho virtual la dirige en tiempo de ejecución al objeto derivado.
Qué significan la sobrecarga y la sobrescritura en C++
La sobrecarga consiste en elegir entre funciones que se distinguen por sus parámetros. La sobrescritura consiste en sustituir un comportamiento dentro de una jerarquía de herencia. El tipo de retorno, por sí solo, no distingue una sobrecarga, y para sobrescribir una función, esta debe ser virtual en la clase base. El especificador override hace que el compilador compruebe que la declaración de la clase derivada realmente coincide con una función virtual de la clase base.
Cómo funciona la sobrecarga de funciones
Declara funciones con el mismo nombre en un ámbito y asígnales listas de parámetros distintas. Las listas pueden diferir en la cantidad o en el tipo de los parámetros. Al llamar a una función, la resolución de sobrecargas considera los argumentos y los tipos de parámetros de las funciones candidatas. El tipo de retorno no se usa para elegir una sobrecarga, así que dos declaraciones que solo difieren en el tipo de retorno no forman un conjunto válido de sobrecargas.
Ejecuta este ejemplo:
El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.
#include <iostream>
class Formatter {
public:
void show(int value) const {
std::cout << "integer: " << value << '\n';
}
void show(double value) const {
std::cout << "decimal: " << value << '\n';
}
};
int main() {
Formatter formatter;
formatter.show(7);
formatter.show(2.5);
}
integer: 7
decimal: 2.5
La evidencia de ejecución proporcionada confirma que este ejemplo se ejecutó correctamente y produjo esa salida. Los argumentos entero y decimal seleccionan distintas sobrecargas de show. Al añadir una sobrecarga, asegúrate de que su lista de parámetros se distinga claramente y de que las llamadas no sean ambiguas.
Cómo funciona la sobrescritura de funciones
Una clase base declara una función virtual; una clase derivada proporciona una función con el mismo nombre y la misma lista de parámetros, y con calificadores y tipo de retorno compatibles. Marca la declaración de la clase derivada con override para que cualquier discrepancia genere un diagnóstico en tiempo de compilación. Cuando la llamada se hace mediante una referencia o un puntero a la clase base, el despacho virtual selecciona la implementación sobrescrita final correspondiente al objeto.
Ejecuta este ejemplo:
El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.
#include <iostream>
class Message {
public:
virtual void print() const {
std::cout << "message\n";
}
};
class Alert : public Message {
public:
void print() const override {
std::cout << "alert\n";
}
};
int main() {
Alert alert;
const Message& message = alert;
message.print();
}
alert
La evidencia de ejecución proporcionada confirma que este ejemplo se ejecutó correctamente y produjo esa salida. Aunque message tiene el tipo de la clase base, hace referencia a un Alert; por eso, la llamada virtual usa Alert::print. Una clase base también puede declarar una función virtual pura con = 0; esa clase es abstracta y no se puede instanciar hasta que las clases derivadas concretas implementen sus funciones virtuales puras.
Sobrecarga y sobrescritura: diferencias clave
| Aspecto | Sobrecarga de funciones | Sobrescritura de funciones |
|---|---|---|
| Propósito | Ofrecer operaciones con el mismo nombre para distintos argumentos | Especializar el comportamiento heredado para un tipo derivado |
| Requisito | Listas de parámetros distintas en el mismo ámbito | Herencia y una función base virtual con una firma compatible |
| Selección | Resolución de sobrecargas en tiempo de compilación según los argumentos de la llamada | Despacho virtual en tiempo de ejecución mediante una referencia o un puntero a la clase base |
| Comprobación útil | Asegurarse de que las llamadas identifiquen la sobrecarga deseada | Añadir override para comprobar que la declaración coincide |
Puede haber sobrecargas sin herencia ni funciones virtuales. La sobrescritura depende de la herencia y del despacho virtual; no se selecciona pasando una lista de argumentos diferente.
Errores comunes y cómo reconocerlos
Una función de una clase derivada con el mismo nombre no sobrescribe automáticamente una función de la clase base. Si la función base no es virtual, la declaración derivada oculta el nombre de la clase base en lugar de habilitar el despacho virtual. Si no coincide un parámetro, el calificador const u otra parte del tipo de función, puede que no se produzca la sobrescritura prevista; escribir override deja esa discrepancia al descubierto en tiempo de compilación.
No intentes crear una sobrecarga cambiando únicamente el tipo de retorno. Evita también pasar objetos derivados por valor cuando esperes un comportamiento polimórfico: al copiarlos en un objeto de la clase base, se pierde la parte derivada. Usa una referencia o un puntero a la clase base para conservar el despacho dinámico. Para la gestión habitual de objetos, prefiere objetos automáticos o punteros inteligentes; si eliminas un objeto derivado a través de un puntero a la clase base, esta debería tener un destructor virtual.