Sobrecarga de função - Function overloading

Em algumas linguagens de programação , a sobrecarga de função ou de método é a capacidade de criar várias funções com o mesmo nome com diferentes implementações. As chamadas para uma função sobrecarregada irão executar uma implementação específica dessa função apropriada ao contexto da chamada, permitindo que uma chamada de função execute tarefas diferentes dependendo do contexto.

Por exemplo, doTask()e doTask(object o)são funções sobrecarregadas. Para chamar o último, um objeto deve ser passado como um parâmetro , enquanto o primeiro não requer um parâmetro e é chamado com um campo de parâmetro vazio. Um erro comum seria atribuir um valor padrão ao objeto na segunda função, o que resultaria em um erro de chamada ambíguo , pois o compilador não saberia qual dos dois métodos usar.

Outro exemplo é uma Print(object o)função que executa ações diferentes com base na impressão de texto ou fotos. As duas funções diferentes podem estar sobrecarregadas como Print(text_object T); Print(image_object P). Se escrevermos as funções de impressão sobrecarregados para todos os objetos do nosso programa vai "imprimir", nunca tem que se preocupar com o tipo do objeto ea correta função chamada novamente, a chamada é sempre: Print(something).

Linguagens que suportam sobrecarga

As linguagens que oferecem suporte à sobrecarga de funções incluem, mas não estão necessariamente limitadas a:

Regras em sobrecarga de função

  • O mesmo nome de função é usado para mais de uma definição de função
  • As funções devem diferir pela aridade ou tipos de seus parâmetros

É uma classificação de polimorfismo estático em que uma chamada de função é resolvida usando algum algoritmo de "melhor correspondência", em que a função específica a ser chamada é resolvida encontrando a melhor correspondência dos tipos de parâmetros formais com os tipos de parâmetros reais. Os detalhes desse algoritmo variam de idioma para idioma.

A sobrecarga de função geralmente está associada a linguagens de programação de tipo estático que impõem a verificação de tipo em chamadas de função . Uma função sobrecarregada é, na verdade, apenas um conjunto de funções diferentes que por acaso têm o mesmo nome. A determinação de qual função usar para uma determinada chamada é resolvida em tempo de compilação .

Em Java , a sobrecarga de função também é conhecida como polimorfismo de tempo de compilação e polimorfismo estático.

A sobrecarga de funções não deve ser confundida com formas de polimorfismo em que a escolha é feita em tempo de execução, por exemplo, por meio de funções virtuais , em vez de estaticamente.

Exemplo: sobrecarga de função em C ++

#include <iostream>

int Volume(int s) {  // Volume of a cube.
  return s * s * s;
}

double Volume(double r, int h) {  // Volume of a cylinder.
  return 3.1415926 * r * r * static_cast<double>(h);
}

long Volume(long l, int b, int h) {  // Volume of a cuboid.
  return l * b * h;
}

int main() {
  std::cout << Volume(10);
  std::cout << Volume(2.5, 8);
  std::cout << Volume(100l, 75, 15);
}

No exemplo acima, o volume de cada componente é calculado usando uma das três funções chamadas "volume", com seleção baseada no número e tipo de parâmetros reais diferentes.

Sobrecarga de construtor

Construtores , usados ​​para criar instâncias de um objeto, também podem ser sobrecarregados em algumas linguagens de programação orientadas a objetos . Como em muitas linguagens o nome do construtor é predeterminado pelo nome da classe, parece que pode haver apenas um construtor. Sempre que vários construtores são necessários, eles devem ser implementados como funções sobrecarregadas. Em C ++ , os construtores padrão não aceitam parâmetros, instanciando os membros do objeto com seus valores padrão apropriados. Por exemplo, um construtor padrão para um objeto de conta de restaurante escrito em C ++ pode definir a gorjeta para 15%:

Bill()
    : tip(0.15), // percentage
      total(0.0)
{ }

A desvantagem disso é que são necessários dois passos para alterar o valor do objeto Bill criado. O seguinte mostra a criação e alteração dos valores dentro do programa principal:

Bill cafe;
cafe.tip = 0.10;
cafe.total = 4.00;

Ao sobrecarregar o construtor, pode-se passar a dica e o total como parâmetros na criação. Isso mostra o construtor sobrecarregado com dois parâmetros. Esse construtor sobrecarregado é colocado na classe, bem como no construtor original que usamos antes. Qual deles é usado depende do número de parâmetros fornecidos quando o novo objeto Bill é criado (nenhum ou dois):

Bill(double tip, double total)
    : tip(tip),
      total(total)
{ }

Agora, uma função que cria um novo objeto Bill poderia passar dois valores para o construtor e definir os membros de dados em uma etapa. O seguinte mostra a criação e configuração dos valores:

Bill cafe(0.10, 4.00);

Isso pode ser útil para aumentar a eficiência do programa e reduzir o comprimento do código.

Outro motivo para a sobrecarga do construtor pode ser a aplicação de membros de dados obrigatórios. Nesse caso, o construtor padrão é declarado privado ou protegido (ou preferencialmente excluído desde C ++ 11 ) para torná-lo inacessível de fora. Para o Bill acima, o total pode ser o único parâmetro do construtor - já que um Bill não tem um padrão sensato para o total - enquanto o padrão da ponta é 0,15.

Complicações

Dois problemas interagem e complicam a sobrecarga de função: mascaramento de nome (devido ao escopo ) e conversão implícita de tipo .

Se uma função é declarada em um escopo e, em seguida, outra função com o mesmo nome é declarada em um escopo interno, existem dois comportamentos de sobrecarga naturais possíveis: a declaração interna mascara a declaração externa (independentemente da assinatura), ou ambas as declarações internas e a declaração externa são ambas incluídas na sobrecarga, com a declaração interna mascarando a declaração externa somente se a assinatura corresponder. O primeiro é obtido em C ++: "em C ++, não há sobrecarga entre os escopos." Como resultado, para obter um conjunto de sobrecarga com funções declaradas em escopos diferentes, é necessário importar explicitamente as funções do escopo externo para o escopo interno, com a usingpalavra - chave.

A conversão de tipo implícita complica a sobrecarga de função porque se os tipos de parâmetros não corresponderem exatamente à assinatura de uma das funções sobrecarregadas, mas puderem corresponder após a conversão de tipo, a resolução depende de qual conversão de tipo é escolhida.

Eles podem se combinar de maneiras confusas: uma correspondência inexata declarada em um escopo interno pode mascarar uma correspondência exata declarada em um escopo externo, por exemplo.

Por exemplo, para ter uma classe derivada com uma função sobrecarregada pegando um doubleou um int, usando a função pegando um intda classe base, em C ++, alguém escreveria:

class B {
 public:
  void F(int i);
};

class D : public B {
 public:
  using B::F;
  void F(double d);
};

Falha ao incluir os usingresultados em um intparâmetro passado para Fa classe derivada sendo convertido em um double e correspondendo à função na classe derivada, em vez de na classe base; Incluir usingresulta em uma sobrecarga na classe derivada e, portanto, corresponder à função na classe base.

Ressalvas

Se um método for projetado com um número excessivo de sobrecargas, pode ser difícil para os desenvolvedores discernir qual sobrecarga está sendo chamada simplesmente lendo o código. Isso é particularmente verdadeiro se alguns dos parâmetros sobrecarregados forem de tipos herdados de outros parâmetros possíveis (por exemplo, "objeto"). Um IDE pode realizar a resolução de sobrecarga e exibir (ou navegar até) a sobrecarga correta.

A sobrecarga baseada em tipo também pode dificultar a manutenção do código, onde as atualizações do código podem alterar acidentalmente a sobrecarga de método escolhida pelo compilador.

Veja também

Referências

links externos