ATÉ ONDE SEI:
O C ++ fornece três tipos diferentes de polimorfismo.
- Funções virtuais
- Sobrecarga de nome de função
- Sobrecarga do operador
Além dos três tipos de polimorfismo acima, existem outros tipos de polimorfismo:
- tempo de execução
- tempo de compilação
- polimorfismo ad-hoc
- polimorfismo paramétrico
Eu sei que o polimorfismo de tempo de execução pode ser alcançado por funções virtuais e o polimorfismo estático pode ser alcançado por funções de modelo
Mas para os outros dois
- polimorfismo ad-hoc
- polimorfismo paramétrico que o site diz ,
polimorfismo ad-hoc:
Se o intervalo de tipos reais que pode ser usado é finito e as combinações devem ser especificadas individualmente antes do uso, isso é chamado de polimorfismo ad-hoc.
polimorfismo paramétrico:
Se todo o código é escrito sem menção de qualquer tipo específico e, portanto, pode ser usado de forma transparente com qualquer número de novos tipos, é chamado de polimorfismo paramétrico.
Eu mal consigo entendê-los :(
alguém pode explicar os dois, se possível, com um exemplo? Espero que as respostas a essas perguntas sejam úteis para muitos novos moradores de suas faculdades.
fonte
Respostas:
Compreensão / requisitos para o polimorfismo
Para entender o polimorfismo - como o termo é usado na Ciência da Computação -, ajuda a começar com um teste simples e sua definição. Considerar:
Aqui,
f()
é realizar alguma operação e receber valoresx
ey
como entradas.Mecanismos C ++ para polimorfismo
Polimorfismo explícito especificado pelo programador
Você pode escrever de
f()
forma que ele possa operar em vários tipos de qualquer uma das seguintes maneiras:Pré-processando:
Sobrecarga:
Modelos:
Expedição virtual:
Outros mecanismos relacionados
O polimorfismo fornecido pelo compilador para tipos incorporados, conversões padrão e conversão / coerção são discutidos posteriormente para fins de completude como:
Terminologia
Categorização adicional
Dados os mecanismos polimórficos acima, podemos categorizá-los de várias maneiras:
Quando o código específico do tipo polimórfico é selecionado?
f
acima comint
argumentos - dependendo do mecanismo polimórfico usado e das opções embutidas para as quais o compilador pode evitar gerar qualquer códigof(double)
, ou o código gerado pode ser jogado fora em algum momento da compilação ou vinculação. ( todos os mecanismos acima, exceto despacho virtual )Quais tipos são suportados?
Significado paramétrico, você pode apenas tentar usar a função para vários tipos de parâmetros sem fazer nada especificamente para permitir seu suporte a eles (por exemplo, modelos, macros). Um objeto com funções / operadores que agem como o modelo / macro espera 1 é tudo o que o modelo / macro precisa para fazer seu trabalho, sendo o tipo exato irrelevante. Os "conceitos" introduzidos pelo C ++ 20 expressam e reforçam essas expectativas - consulte a página cppreference aqui .
O polimorfismo paramétrico fornece tipagem de pato - um conceito atribuído a James Whitcomb Riley, que aparentemente disse: "Quando vejo um pássaro que anda como um pato e nada como um pato e grasna como um pato, eu chamo esse pássaro de pato". .
O polimorfismo do subtipo (também conhecido como inclusão) permite trabalhar em novos tipos sem atualizar o algoritmo / função, mas eles devem ser derivados da mesma classe base (despacho virtual)
1 - Os modelos são extremamente flexíveis. O SFINAE (veja também
std::enable_if
) permite efetivamente vários conjuntos de expectativas para o polimorfismo paramétrico. Por exemplo, você pode codificar que, quando o tipo de dados que você está processando tiver um.size()
membro, você usará uma função, caso contrário, outra função que não precisa.size()
(mas provavelmente sofre de alguma forma - por exemplo, usar o mais lentostrlen()
ou não imprimir como útil uma mensagem no log). Você também pode especificar comportamentos ad-hoc quando o modelo é instanciado com parâmetros específicos, deixando alguns parâmetros paramétricos ( especialização parcial do modelo ) ou não ( especialização completa )."Polimórfico"
Alf Steinbach comenta que no padrão C ++ polimórfico refere-se apenas ao polimorfismo em tempo de execução usando despacho virtual. General Comp. Sci. o significado é mais abrangente, conforme o glossário do criador de C ++, Bjarne Stroustrup ( http://www.stroustrup.com/glossary.html ):
Essa resposta - como a pergunta - relaciona os recursos do C ++ ao Comp. Sci. terminologia.
Discussão
Com o padrão C ++ usando uma definição mais restrita de "polimorfismo" que o Comp. Sci. comunidade, para garantir um entendimento mútuo para o seu público, considere ...
Ainda assim, o que é crucial para ser um ótimo programador de C ++ é entender o que o polimorfismo realmente está fazendo por você ...
permitindo escrever código "algorítmico" uma vez e depois aplicá-lo a muitos tipos de dados
... e esteja ciente de como os diferentes mecanismos polimórficos correspondem às suas necessidades reais.
O polimorfismo em tempo de execução é adequado:
Base*
s,Quando não há um driver claro para o polimorfismo em tempo de execução, as opções em tempo de compilação geralmente são preferíveis. Considerar:
__FILE__
,__LINE__
concatenação literal de cadeias de caracteres e outros recursos exclusivos das macros (que permanecem ruins ;-))Outros mecanismos de apoio ao polimorfismo
Como prometido, para completar, vários tópicos periféricos são abordados:
Esta resposta termina com uma discussão de como as opções acima se combinam para capacitar e simplificar o código polimórfico - especialmente o polimorfismo paramétrico (modelos e macros).
Mecanismos de mapeamento para operações específicas de tipo
> Sobrecargas implícitas fornecidas pelo compilador
Conceitualmente, o compilador sobrecarrega muitos operadores para tipos internos. Não é conceitualmente diferente da sobrecarga especificada pelo usuário, mas é listada, pois é facilmente ignorada. Por exemplo, você pode adicionar ao
int
s edouble
s usando a mesma notaçãox += 2
eo compilador produz:A sobrecarga se estende sem problemas para tipos definidos pelo usuário:
Sobrecargas fornecidas pelo compilador para tipos básicos são comuns em linguagens de computador de alto nível (3GL +), e a discussão explícita do polimorfismo geralmente implica algo mais. (2GLs - linguagens assembly - geralmente exigem que o programador use explicitamente diferentes mnemônicos para diferentes tipos.)
> Conversões padrão
A quarta seção do padrão C ++ descreve as conversões padrão.
O primeiro ponto resume bem (de um rascunho antigo - espero que ainda esteja substancialmente correto):
Conversão zero ou uma do conjunto a seguir: conversão lvalue para rvalue, conversão de matriz em ponteiro e conversão de função em ponteiro.
Conversão zero ou uma do conjunto a seguir: promoções integrais, promoção de ponto flutuante, conversões integrais, conversões de ponto flutuante, conversões integrais flutuantes, conversões de ponteiro, conversões de ponteiro, conversões de ponteiro para membro e conversões booleanas.
Zero ou uma conversão de qualificação.
Essas conversões permitem códigos como:
Aplicando o teste anterior:
a()
ele próprio executa código especificamente paradouble
e, portanto, não é polimórfico.Mas, na segunda chamada para
a()
o compilador sabe para gerar código de tipo apropriado para uma "promoção de ponto flutuante" (Standard §4) para converter42
a42.0
. Esse código extra está na função de chamada . Discutiremos o significado disso na conclusão.> Coerção, elencos, construtores implícitos
Esses mecanismos permitem que as classes definidas pelo usuário especifiquem comportamentos semelhantes às conversões padrão dos tipos internos. Vamos dar uma olhada:
Aqui, o objeto
std::cin
é avaliado em um contexto booleano, com a ajuda de um operador de conversão. Isso pode ser agrupado conceitualmente com "promoções integrais" e outras das conversões padrão no tópico acima.Construtores implícitos efetivamente fazem a mesma coisa, mas são controlados pelo tipo de conversão:
Implicações de sobrecargas, conversões e coerção fornecidas pelo compilador
Considerar:
Se queremos que a quantia
x
seja tratada como um número real durante a divisão (ou seja, 6,5 em vez de arredondada para 6), precisamos apenas mudar paratypedef double Amount
.Isso é bom, mas não teria sido também muito trabalho para tornar o código explicitamente "tipo correto":
Mas considere que podemos transformar a primeira versão em
template
:É por causa desses pequenos "recursos de conveniência" que ele pode ser facilmente instanciado para um
int
ou outrodouble
e funcionar como pretendido. Sem esses recursos, precisaríamos de elencos explícitos, traços de tipo e / ou classes de política, alguma confusão detalhada e propensa a erros como:Portanto, sobrecarga de operador fornecida pelo compilador para tipos internos, conversões padrão, fundição / coerção / construtores implícitos - todos eles contribuem com suporte sutil ao polimorfismo. A partir da definição na parte superior desta resposta, eles abordam "localizando e executando código apropriado ao tipo" mapeando:
"ausente" dos tipos de parâmetros
dos muitos tipos de dados que manipulam códigos algorítmicos polimórficos
para o código escrito para um número (potencialmente menos) de (os mesmos ou outros) tipos.
tipos paramétricos "a" a partir de valores do tipo constante
Eles não estabelecem contextos polimórficos por si mesmos, mas ajudam a capacitar / simplificar o código dentro de tais contextos.
Você pode se sentir enganado ... não parece muito. O significado é que, em contextos polimórficos paramétricos (ou seja, dentro de modelos ou macros), estamos tentando oferecer suporte a uma variedade arbitrariamente grande de tipos, mas geralmente queremos expressar operações sobre eles em termos de outras funções, literais e operações projetadas para um pequeno conjunto de tipos. Reduz a necessidade de criar funções ou dados quase idênticos por tipo quando a operação / valor é logicamente o mesmo. Esses recursos cooperam para adicionar uma atitude de "melhor esforço", fazendo o que é intuitivamente esperado, usando as funções e os dados disponíveis limitados e parando apenas com um erro quando há ambiguidade real.
Isso ajuda a limitar a necessidade de código polimórfico que suporte código polimórfico, criando uma rede mais rígida em torno do uso de polimorfismo, para que o uso localizado não force o uso generalizado e disponibilizando os benefícios do polimorfismo conforme necessário, sem impor os custos de expor a implementação em tempo de compilação, tenha várias cópias da mesma função lógica no código do objeto para dar suporte aos tipos usados e ao realizar expedição virtual em vez de chamadas internas ou, pelo menos, resolvidas em tempo de compilação. Como é típico em C ++, o programador tem muita liberdade para controlar os limites dentro dos quais o polimorfismo é usado.
fonte
dynamic_cast
requer um "ponteiro para ou um valor l de um tipo polimórfico". Cheers & hth.,No C ++, a distinção importante é a ligação em tempo de execução versus em tempo de compilação. Ad-hoc x paramétrico não ajuda muito, como explicarei mais adiante.
Nota - o polimorfismo em tempo de execução ainda pode ser resolvido em tempo de compilação, mas isso é apenas otimização. A necessidade de oferecer suporte à resolução em tempo de execução de maneira eficiente e a negociação com outros problemas faz parte do que levou as funções virtuais a serem o que são. E isso é realmente fundamental para todas as formas de polimorfismo em C ++ - cada uma decorre de diferentes conjuntos de trocas feitas em um contexto diferente.
Sobrecarga de funções e sobrecarga do operador são a mesma coisa em todos os aspectos que importam. Os nomes e a sintaxe para usá-los não afetam o polimorfismo.
Os modelos permitem especificar muitas sobrecargas de função de uma só vez.
Há outro conjunto de nomes para a mesma ideia de tempo de resolução ...
Esses nomes estão mais associados ao OOP, portanto, é um pouco estranho dizer que um modelo ou outra função de não-membro usa ligação antecipada.
Para entender melhor o relacionamento entre funções virtuais e sobrecarga de funções, também é útil entender a diferença entre "despacho único" e "despacho múltiplo". A ideia pode ser entendida como uma progressão ...
Obviamente, há mais no POO do que uma desculpa para nomear um parâmetro como especial, mas essa é uma parte dele. E voltando ao que eu disse sobre compensações - o envio único é bastante fácil de ser feito com eficiência (a implementação usual é chamada de "tabelas virtuais"). O envio múltiplo é mais complicado, não apenas em termos de eficiência, mas também para compilação separada. Se você estiver curioso, pode procurar "o problema da expressão".
Assim como é um pouco estranho usar o termo "ligação antecipada" para funções que não são membros, é um pouco estranho usar os termos "despacho único" e "despacho múltiplo" em que o polimorfismo é resolvido no momento da compilação. Normalmente, considera-se que o C ++ não possui vários despachos, o que é considerado um tipo específico de resolução em tempo de execução. No entanto, a sobrecarga de funções pode ser vista como despacho múltiplo feito em tempo de compilação.
Voltando ao polimorfismo paramétrico x ad-hoc, esses termos são mais populares em programação funcional e não funcionam muito bem em C ++. Mesmo assim...
Polimorfismo paramétrico significa que você tem tipos como parâmetros, e exatamente o mesmo código é usado, independentemente do tipo usado para esses parâmetros.
O polimorfismo ad-hoc é ad-hoc no sentido de que você fornece um código diferente, dependendo dos tipos específicos.
Sobrecarga e funções virtuais são exemplos de polimorfismo ad-hoc.
Novamente, há alguns sinônimos ...
Exceto que estes não são sinônimos, embora sejam comumente tratados como se fossem, e é aí que é provável que ocorra confusão no C ++.
O raciocínio por trás de tratá-los como sinônimos é que, restringindo o polimorfismo a classes particulares de tipos, torna-se possível usar operações específicas para essas classes de tipos. A palavra "classes" aqui pode ser interpretada no sentido de POO, mas realmente se refere apenas a conjuntos de tipos (geralmente nomeados) que compartilham determinadas operações.
Portanto, o polimorfismo paramétrico geralmente é usado (pelo menos por padrão) para implicar polimorfismo irrestrito. Como o mesmo código é usado independentemente dos parâmetros de tipo, as únicas operações suportáveis são aquelas que funcionam para todos os tipos. Ao deixar o conjunto de tipos sem restrições, você limita severamente o conjunto de operações que pode aplicar a esses tipos.
Por exemplo, Haskell, você pode ter ...
O
a
aqui é um tipo polimórfico irrestrito. Pode ser qualquer coisa, então não podemos fazer muito com valores desse tipo.Aqui,
a
é restrito a ser um membro daNum
classe - tipos que agem como números. Essa restrição permite que você faça coisas numéricas com esses valores, como adicioná-los. Até a3
inferência do tipo polimórfica indica que você quer dizer o3
tipoa
.Penso nisso como polimorfismo paramétrico restrito. Há apenas uma implementação, mas ela só pode ser aplicada em casos restritos. O aspecto ad-hoc é a escolha de qual
+
e3
usar. Cada "instância" deNum
possui sua própria implementação distinta. Portanto, mesmo em Haskell, "paramétrico" e "irrestrito" não são realmente sinônimos - não me culpe, não é minha culpa!No C ++, tanto a sobrecarga quanto as funções virtuais são polimorfismos ad-hoc. A definição de polimorfismo ad-hoc não se importa se a implementação é selecionada em tempo de execução ou tempo de compilação.
O C ++ fica muito próximo do polimorfismo paramétrico com modelos se todos os parâmetros do modelo tiverem tipo
typename
. Existem parâmetros de tipo e existe uma única implementação, independentemente de quais tipos são usados. No entanto, a regra "Falha na substituição não é um erro" significa que restrições implícitas surgem como resultado do uso de operações no modelo. Complicações adicionais incluem especialização de modelos para fornecer modelos alternativos - diferentes implementações (ad-hoc).Portanto, de certa forma, o C ++ possui polimorfismo paramétrico, mas é implicitamente restrito e pode ser substituído por alternativas ad-hoc - ou seja, essa classificação realmente não funciona para o C ++.
fonte
a
aqui está um tipo polimórfico irrestrito [...] para que não haja muito que possamos fazer com valores desse tipo". era interessante - em C ++ sans Concepts, você não está restrito a apenas tentar um conjunto específico de operações em um argumento de um tipo especificado como parâmetro de modelo ... bibliotecas como conceitos de otimização funcionam de outra maneira - garantindo que o tipo suporte operações você especifica, em vez de se proteger contra o uso acidental de operações adicionais.Quanto ao polimorfismo ad-hoc, significa sobrecarga de função ou sobrecarga do operador. Confira aqui:
http://en.wikipedia.org/wiki/Ad-hoc_polymorphism
Quanto ao polimorfismo paramétrico, as funções de gabarito também podem ser contadas porque não necessariamente levam parâmetros de tipos FIXED. Por exemplo, uma função pode classificar uma matriz de números inteiros e também pode classificar uma matriz de seqüências de caracteres, etc.
http://en.wikipedia.org/wiki/Parametric_polymorphism
fonte
<
operadores e similares). Em Haskell, você expressar essa exigência explicitamente usando a classeOrd
. O fato de você obter uma diferença<
dependendo do tipo específico (conforme fornecido pela instância deOrd
) seria considerado polimorfismo ad-hoc.Isso pode não ajudar em nada, mas fiz isso para apresentar meus amigos à programação, fornecendo funções definidas, como
START
, eEND
para a função principal, para que não fosse muito assustador (eles usaram apenas o arquivo main.cpp ). Ele contém classes e estruturas polimórficas, modelos, vetores, matrizes, diretivas de pré-processador, amizade, operadores e ponteiros (todos os quais você provavelmente já deve saber antes de tentar o polimorfismo):Nota: ainda não está concluído, mas você pode ter uma ideia
main.cpp
main.h
fonte
Aqui está um exemplo básico usando classes polimórficas
fonte
Polimorfismo significa muitas formas, como tal, é usado para um operador agir de maneira diferente em diferentes instâncias. O polimorfismo é usado para implementar a herança. Por exemplo, definimos um fn draw () para um formato de classe, e o draw fn pode ser implementado para desenhar círculo, caixa, triângulo e outras formas. (que são objetos da forma da classe)
fonte
Se alguém disser corta para essas pessoas
O que vai acontecer?
Então, a representação acima mostra O que é polimorfismo (mesmo nome, comportamento diferente) em OOP.
Se você está indo para uma entrevista e o entrevistador pede que você conte / mostre um exemplo ao vivo para polimorfismo na mesma sala em que estamos, digamos:
Resposta - Porta / Janelas
Querendo saber como?
Através da porta / janela - uma pessoa pode entrar, o ar pode entrar, a luz pode entrar, a chuva pode entrar, etc.
Ou seja, uma forma de comportamento diferente (polimorfismo).
Para entender melhor e de uma maneira simples, usei o exemplo acima. Se você precisar de referência para o código, siga as respostas acima.
fonte