HOWTO · C++
Sobrecarga de funções vs. sobrescrita de funções em C++
Compare a sobrecarga de funções e a sobrescrita de funções em C++, entendendo como cada mecanismo funciona e quando usar cada um.
Nesta página
A sobrecarga de funções e a sobrescrita de funções resolvem problemas diferentes em C++. A sobrecarga de funções permite declarar funções com o mesmo nome no mesmo escopo, mas com listas de parâmetros diferentes; o compilador escolhe a função adequada com base nos argumentos da chamada. A sobrescrita de funções permite que uma classe derivada substitua a implementação herdada de uma função virtual por outra compatível; quando a chamada é feita por uma referência ou um ponteiro para a classe base, o despacho seleciona em tempo de execução a implementação do objeto derivado.
O que significam sobrecarga e sobrescrita em C++
A sobrecarga permite escolher entre funções que diferem nos parâmetros. A sobrescrita permite substituir um comportamento em uma hierarquia de herança. O tipo de retorno, por si só, não diferencia uma sobrecarga, e a sobrescrita exige que a classe base declare uma função virtual. O especificador override faz o compilador verificar se a declaração da classe derivada realmente corresponde a uma função virtual da classe base.
Como funciona a sobrecarga de funções
Declare funções com o mesmo nome no mesmo escopo e listas de parâmetros distintas. As listas podem diferir no número ou nos tipos dos parâmetros. Ao fazer uma chamada, a resolução de sobrecarga considera os argumentos e os tipos de parâmetro das funções candidatas. O tipo de retorno não é usado para escolher uma sobrecarga; por isso, duas declarações que diferem apenas no tipo de retorno não formam um conjunto válido de sobrecargas.
Execute este exemplo:
O código e os rótulos ou saídas exibidos nesta seção permanecem em 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
As evidências de execução fornecidas confirmam que este exemplo foi executado com sucesso e produziu essa saída. Os argumentos inteiro e decimal selecionam sobrecargas diferentes de show. Ao adicionar uma sobrecarga, verifique se a lista de parâmetros difere de forma significativa e se as chamadas continuam sem ambiguidades.
Como funciona a sobrescrita de funções
A classe base declara uma função virtual; a classe derivada fornece uma função com o mesmo nome e a mesma lista de parâmetros, além de qualificadores e tipo de retorno compatíveis. Marque a declaração derivada com override para que uma incompatibilidade gere um diagnóstico em tempo de compilação. Quando a chamada é feita por uma referência ou um ponteiro para a classe base, o despacho virtual seleciona a implementação final correspondente ao objeto.
Execute este exemplo:
O código e os rótulos ou saídas exibidos nesta seção permanecem em 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
As evidências de execução fornecidas confirmam que este exemplo foi executado com sucesso e produziu essa saída. Embora message tenha o tipo da classe base, ele se refere a um Alert; por isso, a chamada virtual usa Alert::print. Uma classe base também pode declarar uma função virtual pura com = 0; essa classe é abstrata e não pode ser instanciada até que classes derivadas concretas implementem suas funções virtuais puras.
Sobrecarga versus sobrescrita: principais diferenças
| Aspecto | Sobrecarga de funções | Sobrescrita de funções |
|---|---|---|
| Finalidade | Oferecer operações com o mesmo nome para argumentos diferentes | Especializar o comportamento herdado em um tipo derivado |
| Requisito | Listas de parâmetros distintas no mesmo escopo | Herança e uma função virtual correspondente na classe base |
| Seleção | Resolução de sobrecarga em tempo de compilação, com base nos argumentos da chamada | Despacho virtual em tempo de execução por uma referência ou um ponteiro para a classe base |
| Verificação útil | Confirmar que as chamadas identificam a sobrecarga pretendida | Adicionar override para verificar se a declaração corresponde à função base |
Pode haver sobrecargas sem herança nem funções virtuais. A sobrescrita depende da herança e do despacho virtual; ela não é selecionada pela passagem de uma lista de argumentos diferente.
Erros comuns e como identificá-los
Uma função derivada com o mesmo nome não sobrescreve automaticamente uma função da classe base. Se a função da classe base não for virtual, a declaração derivada oculta o nome da função base, em vez de habilitar o despacho virtual. Se um parâmetro, o qualificador const ou outra parte do tipo da função não corresponder, a sobrescrita pretendida pode falhar; escrever override revela essa incompatibilidade em tempo de compilação.
Não tente criar uma sobrecarga alterando apenas o tipo de retorno. Evite também passar objetos derivados por valor quando espera comportamento polimórfico: copiá-los para um objeto da classe base remove a parte derivada, um efeito conhecido como fatiamento de objeto. Use uma referência ou um ponteiro para a classe base para preservar o despacho dinâmico. Para gerenciar objetos normalmente, prefira objetos automáticos ou ponteiros inteligentes; se excluir um objeto derivado por meio de um ponteiro para a classe base, essa classe deve ter um destrutor virtual.