Sobrecarga de função em C++ – polimorfismo estático

Sobrecarga de função em C++ ao lado de homem levantando peso.

A sobrecarga de função em C++ é um mecanismo que permite criar várias versões (ou sobrecargas) de uma função em um mesmo escopo, através da modificação do tipo e/ou do número de seus parâmetros. Cada uma dessas versões é chamada de sobrecarga.

A sobrecarga de função em C++, assim como a sobrecarga de operadores em C++, é um exemplo de polimorfismo estático (ou polimorfismo em tempo de compilação). O polimorfismo estático é a característica do C++ que permite ao compilador “escolher” a definição correta de um função que foi sobrecarregada durante a compilação do programa, baseando-se nos argumentos fornecidos na chamada da função.

Vejamos um exemplo de sobrecarga de função em C++ a seguir. Antes disso, note apenas que eu criei objetos de duas classes diferentes como parâmetros de entrada da função printInfo no exemplo 1 para ilustrar a sobrecarga de funções. Todavia, o mesmo efeito (de imprimir objetos diferentes) seria obtido de uma forma melhor através da sobrecarga do operador << nas duas classes (assunto de um próximo artigo).


Exemplo 1 – Sobrecarga de função em C++

#include <iostream>

using namespace std;

class User {
    public:
        User(const std::string& iName, uint iId): id(iId), name(iName) {}
        std::string name {"John Doe"};
        uint id;
};

class Visitor {
    public:
        Visitor(const std::string& iName, const std::string& iEmail): name(iName), email(iEmail) {}
        std::string name {"John Doe Visitor"};
        std::string email {"example@mail.com"};
};


void printInfo(const User& iUser) {
    cout << "User name: " << iUser.name << ".\nUser id: " << iUser.id << endl;
}

void printInfo(const Visitor& iVisitor) {
    cout << "Visitor name: " << iVisitor.name << ".\nVisitor email: " << iVisitor.email << endl;
}

int main()
{
    User bob{"Bob Brown", 1};
    Visitor jose{"Jose Luis", "jose.luis@fakemail.com"};
    
    printInfo(bob);
    printInfo(jose);
    
    return 0;
}

User name: Bob Brown.
User id: 1
Visitor name: Jose Luis.
Visitor email: jose.luis@fakemail.com

Como podemos ver na saída do exemplo 1, a chamada da função printInfo da linha 33: printInfo(bob), executa a versão de printInfo cujo parâmetro de entrada é uma referência constante para o tipo User (linha 20). A prova disso é que na saída lemos “User id: 1”, que não existe na versão de printInfo que recebe uma referência constante para Visitor.

Na linha 34, por sua vez, o programa invoca a segunda versão de printInfo, que funciona com referências constantes para Visitor – posto que o objeto jose é do tipo Visitor. Confirmamos que isso assim acontece observando a saída do programa, que contém “Visitor email: jose.luis@fakemail.com”, texto que não existe na primeira sobrecarga que recebe User.


Sobrecargas inválidas de função em C++

Como foi dito na introdução do artigo, para se obter uma sobrecarga válida de função em C++, é preciso variar o tipo ou a quantidade de parâmetros da função. Não basta, portanto, redefinir a função modificando o seu tipo de retorno, por exemplo: isso resultará em uma sobrecarga ambígua e a compilação falhará por essa mesma razão.

Alguns tipos de modificação na na assinatura de uma função, portanto, não servem para criar uma sobrecarga inequívoca, ou não ambígua, aos olhos do compilador. Os principais tipos de modifições desse tipo estão listados a seguir.

Alterações insuficientes para criar sobrecargas de uma função em C++

  • Modificar o tipo de retorno da função;
  • Adicionar ou remover o modificador const nos parâmetros de entrada da função;
  • Adicionar ou remover o indicador de referência dos parâmetros de entrada da função.

Vamos a um exemplo para entender melhor essa história.


Exemplo 2 – Sobrecargas inválidas de função em C++

#include <iostream>

using namespace std;

int soma(int a, int b) {
    return a + b;
}

// Sobrecarga válida
int soma(double a, double b) {
    return static_cast<int>(a + b);
}

// Erro de compilação: nova declaração de soma
// introduz ambiguidade no programa.
// Sobrecarga inválida #1
double soma(double a, double b) {
    return a + b;
}

// Outra definição ambígua: o const
// não serve para diferenciar parâmetros de entrada em sobrecargas
// Sobrecarga inválida #2
double soma(const double a, const double b) {
    return a + b;
}

// Outra definição ambígua: referências também não
// servem para diferenciar parâmetros de entrada em sobrecargas
double soma(const double& a, const double& b) {
    return a + b;
}

int main()
{
    int x = soma(10, 20); // OK
    double y = soma(10.5, 20.5); // Qual versão chamar? Erro
    
    cout << x << endl;
    cout << y << endl;
    
    return 0;
}

No código acima, a primeira sobrecarga da função soma recebe dois ints e retorna um outro int. Em seguida, na linha 10, defini uma outra sobrecarga da função soma que recebe dois doubles e retorna um int (usando o static_cast para fazer a conversão de double para int) – até aí tudo bem, porque eu mudei o tipo dos parâmetros de entrada de int para double.

O problema surge com a sobrecarga da linha 17, pois nela eu estou criando uma sobrecarga ambígua da versão da linha 10, dado que eu modifiquei apenas o tipo de retorno, que faz parte das alterações insuficientes para criar uma sobrecarga de função em C++. Os outros casos de sobrecargas caem todos na mesma categoria das sobrecargas inválidas.

Próximos passos

Agora que sabemos como funciona a sobrecarga de função em C++, e como modificar funções para criar sobrecargas válidas, é interessante avançar e estudar um tipo especial de polimorfismo estático que é também um tipo de sobrecarga de função, mas de um tipo de função especial: os operadores de classes.

Se não quiser perder o artigo que escreverei acerca da sobrecarga de operadores em C++, se inscreva na nossa newsletter para ficar por dentro dos novos artigos lançados semanalmente.

Foto de perfil de Emanoel

Sou apaixonado por tecnologia, literatura e também filosofia. O cultivo dessas paixões ao longo da minha trajetória me inspiraram a compartilhar aquilo que aprendo com os outros da maneira mais clara que eu possa. Sou formado em Engenharia Elétrica no Brasil, e também sou engenheiro formado na França. Trabalho atualmente como programador C++ em uma multinacional francesa, uma das maiores empresas de TI do mundo.

Leave a Reply

Your email address will not be published. Required fields are marked *