Sobrecarga de função

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

Por exemplo, doTask() e doTask(object o) são funções sobrecarregadas. Para chamar a última, um objeto deve ser passado como um parâmetro , enquanto a primeira não requer um parâmetro e é chamada 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 função Print(object o) que executa ações diferentes com base em se está imprimindo texto ou fotos. As duas funções diferentes podem ser sobrecarregadas como Print(text_object T); Print(image_object P) . Se escrevermos as funções print sobrecarregadas para todos os objetos que nosso programa irá "imprimir", nunca teremos que nos preocupar com o tipo do objeto, e a chamada de função correta novamente, a chamada é sempre: Print(something) .

Idiomas que suportam sobrecarga

As linguagens que suportam sobrecarga de funções incluem, mas não estão necessariamente limitadas, às seguintes:

Regras na sobrecarga de funções

  • O mesmo nome de função é usado para mais de uma definição de função em um módulo, classe ou namespace específico
  • As funções devem ter assinaturas de tipo diferentes , ou seja, diferir no número ou nos tipos de seus parâmetros formais (como em C++) ou adicionalmente em seu tipo de retorno (como em Ada). [9]

A sobrecarga de função é geralmente associada a linguagens de programação estaticamente tipadas que impõem verificação de tipo em chamadas de função . Uma função sobrecarregada é um conjunto de funções diferentes que podem ser chamadas com o mesmo nome. Para qualquer chamada específica, o compilador determina qual função sobrecarregada usar e resolve isso em tempo de compilação . Isso é verdade para linguagens de programação como Java. [10]

A sobrecarga de funções difere das 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++

#incluir <iostream> 

int Volume ( int s ) { // Volume de um cubo. return s * s * s ; }     
       


double Volume ( double r , int h ) { // Volume de um cilindro. return 3.1415926 * r * r * static_cast < double > ( h ); }       
         


long Volume ( long l , int b , int h ) { // Volume de um cuboide. 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 denominadas "volume", com seleção baseada no número e tipo diferentes de parâmetros reais.

Sobrecarga do 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 forem necessários, eles devem ser implementados como funções sobrecarregadas. Em C++ , construtores padrão não aceitam parâmetros, instanciando os membros do objeto com seus valores padrão apropriados, "que normalmente é zero para campos numéricos e string vazia para campos de string". [11] Por exemplo, um construtor padrão para um objeto de conta de restaurante escrito em C++ pode definir a gorjeta para 15%:

Bill () 
: gorjeta ( 0,15 ), // porcentagem total ( 0,0 ) { }      
      
 

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

Conta café ; café . gorjeta = 0,10 ; café . total = 4,00 ; 
  
  

Ao sobrecarregar o construtor, pode-se passar a ponta e o total como parâmetros na criação. Isso mostra o construtor sobrecarregado com dois parâmetros. Esse construtor sobrecarregado é colocado na classe, assim como o 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):

Conta ( gorjeta dupla , total duplo ) : gorjeta ( gorjeta ), total ( total ) { }   
     
      
 

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

Conta café ( 0,10 , 4,00 );  

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

Outra razão para sobrecarga do construtor pode ser impor membros de dados obrigatórios. Neste 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, total pode ser o único parâmetro do construtor – já que um Bill não tem um padrão sensato para total – enquanto tip tem o padrão de 0,15.

Complicações

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

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

A conversão implícita de tipos complica a sobrecarga de funções 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 tipos, a resolução dependerá de qual conversão de tipos for 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. [12]

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

classe B { público : void F ( int i ); };  
 
    


classe D : público B { público : usando B :: F ; vazio F ( duplo d ); };     
 
   
    

Deixar de incluir os usingresultados em um intparâmetro passado Fna 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, correspondendo à função na classe base.

Advertências

Se um método for projetado com um número excessivo de sobrecargas, pode ser difícil para os desenvolvedores discernirem qual sobrecarga está sendo chamada simplesmente lendo o código. Isso é particularmente verdadeiro se alguns dos parâmetros sobrecarregados forem de tipos que são tipos herdados de outros parâmetros possíveis (por exemplo, "objeto"). Um IDE pode executar 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 qual sobrecarga de método é escolhida pelo compilador. [13]

Veja também

Citações

  1. ^ "Clojure - Aprenda Clojure - Funções". clojure.org . Recuperado em 2023-06-13 .
  2. ^ "Especificação da linguagem Kotlin". kotlinlang.org .
  3. ^ Bloch 2018, p. 238-244, §Capítulo 8 Item 52: Elimine avisos não verificados.
  4. ^ "37.6. Sobrecarga de função". Documentação do PostgreSQL . 2021-08-12 . Recuperado em 2021-08-29 .
  5. ^ "Guia do usuário e referência do banco de dados PL/SQL". docs.oracle.com . Recuperado em 29/08/2021 .
  6. ^ "Manual Nim". nim-lang.org .
  7. ^ "Documentos de Cristal". crystal-lang.org .
  8. ^ "Embarcadero Delphi". embarcadero.com .
  9. ^ Watt, David A.; Findlay, William (1 de maio de 2004). Conceitos de design de linguagem de programação . John Wiley & Sons, Inc. pp. 204–207. ISBN 978-0-470-85320-7.
  10. ^ Bloch 2018, p. 238-244, §Capítulo 8 Item 52: Use a sobrecarga criteriosamente.
  11. ^ Chan, Jamie (2017). Aprenda C# em um dia e aprenda bem (edição revisada). p. 82. ISBN 978-1518800276.
  12. ^ ab Stroustrup, Bjarne . "Por que a sobrecarga não funciona para classes derivadas?".
  13. ^ Bracha, Gilad (3 de setembro de 2009). "Sobrecarga sistêmica". Sala 101.

Referências

  • Bloch, Joshua (2018). "Effective Java: Programming Language Guide" (terceira edição). Addison-Wesley. ISBN 978-0134685991.
  • Meyer, Bertrand (outubro de 2001). "Overloading vs Object Technology" (PDF) . Coluna Eiffel. Journal of Object-Oriented Programming . 14 (4). 101 Communications LLC: 3–7 . Recuperado em 27 de agosto de 2020 .
Retrieved from "https://en.wikipedia.org/w/index.php?title=Function_overloading&oldid=1240983506"