Cerca di descrivere il polimorfismo più facile che puoi

In che modo il polimorfismo può essere descritto in un modo facile da capire?

Possiamo trovare molte informazioni sull’argomento su Internet e sui libri, come nel polimorfismo di tipo . Ma proviamo a renderlo il più semplice ansible.

Questo è dalla mia risposta da una domanda simile. Ecco un esempio di polimorfismo in pseudo-C # / Java:

class Animal { abstract string MakeNoise (); } class Cat : Animal { string MakeNoise () { return "Meow"; } } class Dog : Animal { string MakeNoise () { return "Bark"; } } Main () { Animal animal = Zoo.GetAnimal (); Console.WriteLine (animal.MakeNoise ()); } 

Il metodo Main () non conosce il tipo di animale e dipende dal comportamento di un’implementazione particolare del metodo MakeNoise ().

Due oggetti rispondono allo stesso messaggio con comportamenti diversi; il mittente non deve preoccuparsi.

Ogni lattina con un semplice coperchio pop si apre allo stesso modo.
Come umano, sai che puoi Open () qualsiasi che puoi trovare.

Quando è aperto, non tutte le lattine si comportano nello stesso modo.
Alcuni contengono noci, altri contengono serpenti falsi che spuntano fuori.
Il risultato dipende dal TIPO di lattina, se il barattolo era un “CanOfNuts” o un “CanOfSnakes”, ma questo non ha alcuna influenza su COME lo apri. Sai solo che puoi aprire qualsiasi Can e otterrai una sorta di risultato che viene deciso in base al tipo di Can che è stato aperto.

pUnlabledCan-> Open (); // potrebbe dare noci, potrebbe dare serpenti. Non lo sappiamo finché non lo chiamiamo

Open () ha un tipo di ritorno generico di “Contenuti” (o potremmo decidere di non restituire il tipo), in modo che l’apertura abbia sempre la stessa firma di funzione.

Tu, l’umano, sei l’utente / chiamante.
Open () è la funzione virtuale / polimorfica.
“Can” è la class base astratta.
CanOfNuts e CanOfSnakes sono i figli polimorfici della class “Can”.
Ogni Can può essere aperto, ma ciò che specificamente fa e quale specifico contenuto di contenuti restituisce sono definiti da che tipo di può essere.
Tutto quello che sai quando vedi pUnlabledCan è che puoi aprirlo () e restituirà il contenuto. Qualsiasi altro comportamento (come i serpenti che scoppiettano in faccia) sono decisi dallo specifico Can.

La descrizione più semplice del polimorfismo è che è un modo per ridurre le istruzioni if ​​/ switch .

Ha anche il vantaggio di permetterti di estendere le tue dichiarazioni if ​​/ switch (o di altre persone) senza modificare le classi esistenti.

Ad esempio, considera la class Stream in .NET. Senza polimorfismo sarebbe una singola class di grandi dimensioni in cui ogni metodo implementa un’istruzione switch come:

 public class Stream { public int Read(byte[] buffer, int offset, int count) { if (this.mode == "file") { // behave like a file stream } else if (this.mode == "network") { // behave like a network stream } else // etc. } } 

Invece permettiamo al runtime di effettuare il passaggio per noi in modo più efficiente, scegliendo automaticamente l’implementazione in base al tipo concreto ( FileStream , NetworkStream ), ad es.

 public class FileStream : Stream { public override int Read(byte[] buffer, int offset, int count) { // behave like a file stream } } public class NetworkStream : Stream { public override int Read(byte[] buffer, int offset, int count) { // behave like a network stream } } 

Poly: molti
Morfismo: forms / forms

L’attore contro il personaggio (o ruolo)

Le mele e le arance sono entrambi frutto. La frutta può essere mangiata. Quindi, sia le mele che le arance possono essere mangiate.

Il calciatore? Li mangi in modo diverso! Sbuccia le arance, ma non le mele.

Quindi l’implementazione è diversa, ma il risultato finale è lo stesso, si mangia la frutta .

Se cammina come un’anatra e caga come un’anatra, allora puoi trattarla come un’anatra ovunque ti serva un’anatra.

Questo è un articolo migliore in realtà

Il polimorfismo consente agli oggetti di “guardare” lo stesso, ma si comportano in modi diversi. Il solito esempio è di prendere una class di base animale con un metodo Speak (), una sottoclass di cani emetterebbe una corteccia mentre una sottoclass di maiale emetterebbe un grugnito.

La risposta breve di 5 secondi che la maggior parte delle persone usa per far sì che altri sviluppatori riescano a capovolgere il Polymorphism è sovraccarico e preponderante

Stessa syntax, semantica diversa.

Il modo più semplice per descriverlo: un verbo che può essere applicato a più di un tipo di object.

Tutto il resto, come ha detto Hillel, è solo un commento.

Il polimorfismo tratta le cose in modo astratto facendo affidamento sulla conoscenza di un comune “genitore” (pensa a gerarchie come Animal come genitore di Cani e Gatti).

Ad esempio, tutti gli Animali possono respirare ossigeno, e mentre ciascuno di loro può farlo in modo diverso, è ansible progettare una struttura che fornisce ossigeno agli animali per respirare, supportando sia cani che gatti.

Come un piccolo extra, puoi farlo anche se Animal è un identificatore “astratto” (non esiste una vera cosa “Animale”, solo tipi di Animali).

Il polimorfismo è la memorizzazione di valori di più di un tipo in una posizione di un singolo tipo.

Si noti che la maggior parte delle altre risposte a questa domanda, al momento della mia scrittura, stanno effettivamente descrivendo dispatch dinamico, non polimorfismo.

La spedizione dynamic richiede polimorfismo, ma il contrario non è vero. Si potrebbe immaginare un linguaggio molto simile a Java o C # ma di cui System.Object non aveva membri; il typecasting sarebbe necessario prima di fare qualsiasi cosa con il valore. In questo linguaggio figurativo, ci sarebbe il polimorfismo, ma non necessariamente i metodi virtuali, o qualsiasi altro meccanismo di invio dinamico.

L’invio dinamico è il concetto correlato ma distinto, descritto abbastanza bene nella maggior parte delle altre risposte. Tuttavia, il modo in cui normalmente funziona nei linguaggi orientati agli oggetti (selezionando una funzione basata sul primo tipo di argomento (‘this’ o ‘Self’)) non è l’unico modo in cui può funzionare. È anche ansible la spedizione multipla , in cui la selezione viene applicata attraverso i tipi di tutti gli argomenti.

Allo stesso modo, la risoluzione del sovraccarico e il dispacciamento multiplo sono degli analoghi gli uni rispetto agli altri; la risoluzione di sovraccarico è una distribuzione multipla applicata a tipi statici, mentre la distribuzione multipla è la risoluzione di sovraccarico applicata ai tipi di runtime memorizzati in posizioni polimorfiche.

Il polimorfismo sta dividendo il mondo in scatole basate su proprietà comuni e trattando gli oggetti in una determinata casella come intercambiabili quando si desidera utilizzare solo queste proprietà comuni.

Il polimorfismo è la capacità di trattare cose diverse come se fossero la stessa cosa stabilendo un’id quadro condivisa tra loro e poi sfruttandola.

Il polimorfismo è ciò che ottieni quando lo stesso metodo si applica a più classi. Ad esempio, sia una stringa che una lista potrebbero avere metodi “inversi”. Entrambi i metodi hanno lo stesso nome (“Reverse”). Entrambi i metodi fanno qualcosa di molto simile (invertire tutti i caratteri o invertire l’ordine degli elementi nell’elenco). Ma l’implementazione di ciascun metodo “Reverse” è diversa e specifica per la sua class. (In altre parole, la stringa si inverte come una stringa e la lista si inverte come una lista.)

Per usare una metafora, potresti dire “Fai cena” ad uno chef francese o ad uno chef giapponese. Ognuno eseguiva “cena” nel proprio modo caratteristico.

Il risultato pratico è che è ansible creare un “Motore di inversione” che accetta un object e chiama “Reverse” su di esso. Finché l’object ha un metodo Reverse, il tuo motore di inversione funzionerà.

Per estendere l’analogia con lo chef, potresti creare un “Waiterbot” che dice agli chef di “Preparare la cena”. The Waiterbot non deve sapere che tipo di cena sarà fatta. Non ha nemmeno bisogno di assicurarsi che stia parlando con uno chef. Tutto ciò che conta è che lo “chef” (o vigile del fuoco, distributore automatico o distributore di cibo per animali) sa cosa fare quando gli viene detto di “Preparare la cena”.

Ciò che questo ti compra come programmatore è costituito da un minor numero di righe di codice e dal tipo di sicurezza o di associazione tardiva. Ad esempio, ecco un esempio di sicurezza del tipo e associazione anticipata (in un linguaggio simile a quello che sto inventando mentre procedo):

 class BankAccount { void SubtractMonthlyFee } class CheckingAccount : BankAccount {} class SavingsAccount : BankAccount {} AssessFee(BankAccount acct) { // This will work for any class derived from // BankAccount; even classs that don't exist yet acct.SubtractMonthlyFee } main() { CheckingAccount chkAcct; SavingsAccount saveAcct; // both lines will compile, because both accounts // derive from "BankAccount". If you try to pass in // an object that doesn't, it won't compile, EVEN // if the object has a "SubtractMonthlyFee" method. AssessFee(chkAcct); AssessFee(saveAcct); } 

Ecco un esempio senza sicurezza di tipo ma con rilegatura tardiva:

 class DatabaseConnection { void ReleaseResources } class FileHandle { void ReleaseResources } FreeMemory(Object obj) { // This will work for any class that has a // "ReleaseResources" method (assuming all // classs are ultimately derived from Object. obj.ReleaseResources } main() { DatabaseConnection dbConn; FileHandle fh; // You can pass in anything at all and it will // compile just fine. But if you pass in an // object that doesn't have a "ReleaseResources" // method you'll get a run-time error. FreeMemory(dbConn); FreeMemory(fh); FreeMemory(acct); //FAIL! (but not until run-time) } 

Per un esempio eccellente, guarda il metodo .NET ToString (). Tutte le classi ce l’hanno perché tutte le classi derivano dalla class Object. Ma ogni class può implementare ToString () in un modo che ha senso per se stesso.

EDIT: Simple! = Short, IMHO

Il polimorfismo è una funzionalità linguistica che consente al codice algoritmico di alto livello di operare invariato su più tipi di dati.

Ciò avviene assicurando che le operazioni invochino l’implementazione corretta per ogni tipo di dati. Anche in un contesto OOP (come nel tag di questa domanda), questa “corretta implementazione” può essere risolta in fase di compilazione o in fase di esecuzione (se la tua lingua supporta entrambi). In alcuni linguaggi come il C ++, il supporto fornito dal compilatore per il polimorfismo di run-time (es. Dispatch virtuale) è specifico per OOP, mentre altri tipi di polimorfismo possono operare anche su tipi di dati che non sono oggetti (cioè non struct o istanze di class , ma può essere incorporato in tipi come int o double ).

(I tipi di polimorfismo supportati da C ++ sono elencati e contrapposti nella mia risposta: Polymorphism in c ++ – anche se si programmano altri linguaggi, è potenzialmente istruttivo)

Il modo in cui provo a pensarlo è qualcosa che sembra uguale ma può avere funzionalità diverse a seconda dell’istanza. Quindi puoi avere un tipo

 interface IJobLoader 

ma a seconda di come viene utilizzato può avere funzionalità diverse pur mantenendo lo stesso aspetto. Potresti avere istanze per BatchJobLoader, NightlyJobLoader ecc

Forse sono lontano.

Il termine polimorfismo può essere applicato anche alle funzioni di sovraccarico. Per esempio,

 string MyFunc(ClassA anA); string MyFunc(ClassB aB); 

è un esempio di polimorfismo non orientato agli oggetti.

È la capacità che gli oggetti devono rispondere allo stesso messaggio in modi diversi.

Ad esempio, in linguaggi come smalltalk, Ruby, Objective-C, devi solo inviare il messaggio e loro risponderanno.

  dao = XmlDao.createNewInstance() #obj 1 dao.save( data ) dao = RdbDao.createNewnewInstance() #obj 2 dao.save( data ) 

In questo esempio, due oggetti diversi hanno risposto in modo diverso agli stessi messaggi: “createNewInstance () e save (obj)”

Agiscono in modi diversi, allo stesso messaggio. Nelle lingue sopra elencate, le classi potrebbero non essere nemmeno nella stessa gerarchia di classi, è sufficiente che rispondano al messaggio.

In linguaggi come Java, C ++, C # ecc. Per assegnare l’object a un riferimento a un object, è necessario condividere la stessa gerarchia di tipi implementando l’interfaccia o sottoclass di una class comune.

facile .. e semplice.

Il polimorfismo è di gran lunga la caratteristica più importante e rilevante della programmazione orientata agli oggetti.

È un modo per trattare cose diverse che possono fare qualcosa di simile nello stesso modo senza preoccuparsi di come lo fanno.

Supponiamo che tu abbia un gioco con un sacco di diversi tipi di veicoli in giro come Auto, Camion, Skateboard, Aereo, ecc. Tutti possono fermarsi, ma ogni veicolo si ferma in un modo diverso. Alcuni veicoli potrebbero dover cambiare marcia, e alcuni potrebbero essere in grado di fermarsi per un periodo freddo. Il polimorfismo ti consente di farlo

 foreach (Vehicle v in Game.Vehicles) { v.Stop(); } 

Il modo in cui viene implementato lo stop viene rimandato ai diversi veicoli in modo che il tuo programma non debba preoccuparsene.

È solo un modo per invecchiare per chiamare il nuovo codice. Scrivi alcune applicazioni che accettano un’interfaccia “Shape” con metodi che altri devono implementare (esempio: getArea). Se qualcuno ti presenta un nuovo modo per implementare quell’interfaccia, il vecchio codice può chiamare quel nuovo codice tramite il metodo getArea.

La capacità di un object di un certo tipo (ad esempio un’auto) di agire (ad esempio un freno) come uno di un altro tipo (ad esempio un veicolo) che di solito suggerisce una discendenza comune (ad esempio, l’auto è un sottotipo di veicolo) in un punto della gerarchia di tipi .

Il polimorfismo è la soluzione orientata agli oggetti al problema del passaggio di una funzione a un’altra funzione. In C puoi farlo

  void h() { float x=3.0; printf("%f", x); } void k() { int y=5; printf("%i", y); } void g(void (*f)()) { f(); } g(h); // output 3.0 g(k); // output 5 

In C le cose si complicano se la funzione dipende da parametri aggiuntivi. Se le funzioni hek dipendono da diversi tipi di parametri, sei nei guai e devi usare il cast. Devi memorizzare quei parametri in una struttura dati e passare un puntatore a quella struttura dati a g che lo passa ad h o k. hek lancia il puntatore in un puntatore alla struttura corretta e decomprime i dati. Molto disordinato e molto pericoloso a causa di possibili errori di trasmissione:

  void h(void *a) { float* x=(float*)a; printf("%f",*x); } void k(void *a) { int* y=(int*)a; printf("%i",*y); } void g(void (*f)(void *a),void *a) { f(a); } float x=3.0; int y=5; g(h,&x); // output x g(k,&y); // output y 

Così hanno inventato il polimorfismo. h e k sono promossi alle classi e le effettive funzioni ai metodi, i parametri sono variabili membro della rispettiva class, h o k. Invece di passare la funzione, si passa un’istanza della class che contiene la funzione desiderata. L’istanza contiene i propri parametri.

 class Base { virtual public void call()=0; } class H : public Base { float x; public void call() { printf("%f",x);} } h; class K : public Base { int y; public void call() { printf("%i",y);} } k; void g(Base &f) { f.call(); }; hx=3.0; ky=5; g(h); // output hx g(k); // output kx