🔁 Sobrecarga de Funções · Polimorfismo Estático · C++

🔁 Sobrecarga de Funções

"Sobrecarga de funções (function overloading) é a capacidade de definir múltiplas funções com o mesmo nome, mas com diferentes listas de parâmetros. O compilador decide qual versão chamar com base nos argumentos fornecidos."

A sobrecarga de funções é uma forma de polimorfismo estático (em tempo de compilação). Ela permite criar interfaces intuitivas e consistentes, onde o mesmo nome de função pode operar com diferentes tipos ou quantidades de argumentos.

📌 Conceito Básico

Funções sobrecarregadas devem diferir em pelo menos um destes aspectos:

  • Número de parâmetros
  • Tipos dos parâmetros
  • Ordem dos tipos dos parâmetros

O tipo de retorno sozinho NÃO é suficiente para distinguir sobrecargas.

// Sobrecargas válidas (diferem nos parâmetros) int somar(int a, int b) { return a + b; } double somar(double a, double b) { return a + b; } int somar(int a, int b, int c) { return a + b + c; } // ERRO: apenas o tipo de retorno difere (não compila!) // int calcular(int x) { return x * 2; } // double calcular(int x) { return x * 2.0; } // ERRO! int main() { cout << somar(5, 3) << endl; // Chama somar(int, int) cout << somar(2.5, 3.7) << endl; // Chama somar(double, double) cout << somar(1, 2, 3) << endl; // Chama somar(int, int, int) }

⚙️ Como o Compilador Resolve a Sobrecarga

O processo de resolução de sobrecarga segue uma série de etapas para encontrar a "melhor correspondência":

  1. Correspondência exata: Tipos idênticos ou triviais (ex.: intint, intconst int).
  2. Promoção: Conversões que não perdem dados (ex.: charint, floatdouble).
  3. Conversão padrão: Conversões que podem perder dados (ex.: intfloat, doubleint).
  4. Conversão definida pelo usuário: Construtores e operadores de conversão.
void f(int x) { cout << "f(int)" << endl; } void f(double x) { cout << "f(double)" << endl; } int main() { f(5); // Correspondência exata: f(int) f(5.0); // Correspondência exata: f(double) f('A'); // Promoção: char → int → f(int) f(5L); // Conversão padrão: long → int OU long → double? Ambíguo! }

⚠️ Ambiguidades na Sobrecarga

Quando o compilador não consegue decidir qual sobrecarga é a melhor, ocorre um erro de ambiguidade.

void f(int x, double y) { cout << "f(int, double)" << endl; } void f(double x, int y) { cout << "f(double, int)" << endl; } int main() { f(5, 3); // ERRO! Ambíguo: f(int, double) ou f(double, int)? f(5.0, 3.0); // ERRO! Ambíguo } // Outro exemplo clássico de ambiguidade void g(int x) { } void g(int& x) { } // ERRO! Não pode sobrecarregar apenas por referência

🔄 Sobrecarga com Parâmetros Padrão

Cuidado ao combinar sobrecarga com valores padrão — pode criar ambiguidades.

void h(int x) { cout << "h(int)" << endl; } void h(int x, int y = 10) { cout << "h(int, int)" << endl; } int main() { h(5); // ERRO! Ambíguo: h(int) ou h(int, int) com y padrão? h(5, 20); // OK: chama h(int, int) }

📦 Sobrecarga de Operadores

A sobrecarga também se aplica a operadores (+, -, <<, etc.), permitindo que trabalhem com tipos definidos pelo usuário.

class Complexo { double real, imag; public: Complexo(double r, double i) : real(r), imag(i) {} // Sobrecarga do operador + Complexo operator+(const Complexo& outro) const { return Complexo(real + outro.real, imag + outro.imag); } // Sobrecarga do operador << (função amiga) friend std::ostream& operator<<(std::ostream& os, const Complexo& c); }; std::ostream& operator<<(std::ostream& os, const Complexo& c) { os << c.real << " + " << c.imag << "i"; return os; } int main() { Complexo a(1, 2), b(3, 4); Complexo c = a + b; // Chama operator+ cout << c << endl; // Chama operator<< → "4 + 6i" }

📊 Sobrecarga vs. Templates

CaracterísticaSobrecargaTemplates
Quando o código é geradoCompilação (funções separadas)Instanciação (sob demanda)
Número de versõesFinito, definido pelo programadorPotencialmente infinito
Controle sobre tiposTotal (cada versão é explícita)Genérico (funciona com qualquer tipo compatível)
Mensagens de erroGeralmente mais clarasPodem ser complexas
Quando usarPoucas variações conhecidasAlgoritmos genéricos

💡 Boas Práticas

  • Use sobrecarga para criar interfaces intuitivas — o usuário não precisa lembrar nomes diferentes para operações similares.
  • Mantenha a semântica consistente — todas as sobrecargas devem fazer essencialmente a mesma coisa.
  • Evite ambiguidades — cuidado com combinações de tipos que podem ser convertidos entre si.
  • Prefira sobrecarga a funções com nomes diferentes quando a operação for a mesma.
  • Considere templates se a implementação for idêntica para muitos tipos.
  • Documente as sobrecargas — explique o que cada versão faz e quando é chamada.

🔗 Conclusão

A sobrecarga de funções é um dos pilares da expressividade em C++. Ela permite criar APIs limpas e intuitivas, onde o mesmo nome de função se adapta naturalmente a diferentes contextos. Combinada com sobrecarga de operadores e templates, forma a base para bibliotecas poderosas e fáceis de usar. Compreender as regras de resolução de sobrecarga ajuda a evitar ambiguidades e a escrever código que se comporta exatamente como esperado.

✅ Esta foi a última página da lista! Todos os 27 tópicos foram concluídos com sucesso.

Postar um comentário

0 Comentários