Polimorfisme (informàtica)

De la Viquipèdia, l'enciclopèdia lliure.
Saltar a la navegació Saltar a la cerca

En informàtica , el terme polimorfisme (del grec πολυμορφος compost pels termes πολυ very i μορφή per tant forma "tenir moltes formes") s'utilitza en un sentit genèric per referir-se a expressions que poden representar valors de diferents tipus (anomenats expressions polimòrfiques ). En un llenguatge sense tipus , totes les expressions són intrínsecament polimòrfiques.

El terme s’associa a dos significats específics:

  • en el context de la programació orientada a objectes , es refereix al fet que una expressió el tipus de la qual sigui descrita per una classe A pot prendre valors de qualsevol tipus descrits per una subclasse de classe B de A ( polimorfisme per inclusió );
  • en el context de la programació genèrica , es refereix al fet que el codi del programa pot rebre un tipus com a paràmetre en lloc de conèixer-lo a priori ( polimorfisme paramètric ).

Polimorfisme per inclusió

Normalment es vincula a les relacions d’herència entre classes, cosa que garanteix que aquests objectes, fins i tot de diferents tipus, tinguin la mateixa interfície : en llenguatges d’objectes mecanografiats es poden utilitzar instàncies d’una subclasse en lloc d’instàncies de la superclasse ( polimorfisme per inclusió). ).

Els mètodes o propietats de substitució permeten que els objectes que pertanyen a subclasses de la mateixa classe responguin de manera diferent als mateixos usos. Per exemple, suposem que teniu una jerarquia en què les classes Cane i Gatto provenen de la superclasse Animale . Aquest últim defineix un mètode de cosa per cosaMangia() , les especificacions del qual són: Retorna una cadena que identifica el nom del menjar típic de l'animal. Els dos mètodes cosaMangia() definits a les classes Cane i Gatto anul·len el que hereten d’ Animale i, respectivament, retornen dos resultats diferents en funció del tipus real de l’objecte al qual s’invoca el mètode. Per tant, el comportament d'un programa bastant complex es pot modificar considerablement en funció de les subclasses que s'instancien en temps d'execució i les instàncies de les quals passen a les diverses parts del codi.

Els mètodes que es redefineixen en una subclasse s’anomenen polimòrfics , ja que el mateix mètode es comporta de manera diferent en funció del tipus d’objecte al qual s’invoca.

En els idiomes on les variables no tenen cap tipus, com ara Ruby , Python i Smalltalk , no hi ha cap comprovació sintàctica dels mètodes que es poden invocar ( escriptura d'ànec ). D’una banda, això amplia les possibilitats del polimorfisme més enllà de les relacions d’herència: a l’exemple anterior, les classes Cane i Gatto no necessiten ser subclasses d’ Animale , perquè als clients només els importa que els tres tipus exposin el mateix mètode amb el nom cosaMangia i la llista d'arguments buits. D'altra banda, això augmenta la possibilitat d'errors en temps d'execució, ja que no és possible forçar les classes a respectar la interfície comuna i, per tant, un possible error no és identificat pel compilador (amb la consegüent negativa a compilar), sinó només quan un client determinat intentarà utilitzar un mètode o atribut que no existeix o que es defineix de manera que no s’ajusta a les especificacions.

Beneficis

El polimorfisme d’inclusió permet al programa fer ús d’objectes que exposen la mateixa interfície, però implementacions diferents. De fet, la interfície de tipus base defineix un contracte general que diferents subclasses poden satisfer de maneres diferents, però totes s’ajusten a l’especificació comuna establerta pel tipus de base. En conseqüència, la part del programa que utilitza aquesta interfície (anomenada client en argot) tracta tots els objectes que proporcionen un determinat conjunt de serveis de manera homogènia, independentment de les seves implementacions internes (presumiblement diferents entre si) definides per les seves respectives classes. . En virtut d’aquesta possibilitat, és possible utilitzar el mateix codi personalitzant o fins i tot modificant radicalment el seu comportament, sense haver-lo de reescriure, sinó simplement proporcionant-lo com a entrada amb una implementació diferent del tipus bàsic o dels tipus bàsics.

Si s’utilitza bé, el polimorfisme permet una estructura d’objectes

  • extensible , ja que es pot induir al client a invocar nous mètodes personalitzats incloent-los en una classe especial;
  • resistent , perquè qualsevol necessitat futura del programa o per escrit del codi es pot implementar proporcionant a un client ja escrit una nova classe escrita ad hoc .

Cas inicial: les xifres

Suposem que voleu desenvolupar un programa capaç de dibuixar polígons d’una mida determinada a la pantalla. Cada polígon s'ha de dibuixar d'una manera diferent, utilitzant les biblioteques proporcionades pel llenguatge utilitzat.

Com que en temps d' execució no sabrem exactament quants i quins polígons haurem de dibuixar, és necessari que el compilador pugui rastrejar el quadrat , el cercle , el pentàgon, etc. fins al mateix objecte, per tal de reconèixer els mètodes utilitzats . Per fer-ho declarem una classe base Figure, de la qual heretaran les propietats totes les altres.

La classe base

Exemple (llenguatge Visual Basic ):

 Figura pública de classe MustInherit

Sub sorteig públic de MustOverride ()
Perímetre públic de la funció MustOverride () com a doble
Àrea de funció pública MustOverride () com a doble

Classe final

Acabem de declarar una classe que s’ha d’heretar d’altres classes i no s’ha d’utilitzar mai com a classe base, l’anomenada classe abstracta. A més, els mètodes han de ser anul·lats per les classes que en hereten. Un cop fet això, podem implementar totes les xifres que desitgem.

Algunes classes derivades

L'exemple següent omet les implementacions d'alguns membres

 Plaça de classe pública
  Figura d’ herències

  Com a part privada Doble

  Subpublic públic Nou ( com a doble cara )
  ...
  Finalitzar sub
  Propietat pública Lato () com a doble
  ...
  Propietat final

  Sub sorteig de substitucions públiques ()
  Inseriu aquí les instruccions per dibuixar un quadrat segons les biblioteques gràfiques
  ...
  Finalitzar sub
  Perímetre de funció de substitució pública () com a doble
    Tornada lateral * 4
  Funció final
  Àrea de funció de substitució pública () com a doble
    Tornar costat * costat
  Funció final
Classe final

Cercle de classe pública
  Figura d’ herències

  Radi privat com a doble

  Subpúblic públic nou ( radi com a doble )
  ...
  Finalitzar sub
  Radi de la propietat pública () com a doble
  ...
  Propietat final

  Sub sorteig de substitucions públiques ()
  Inseriu aquí les instruccions per dibuixar un cercle segons les biblioteques gràfiques
  ...
  Finalitzar sub
  Perímetre de funció de substitució pública () com a doble
    Radi de retorn * 2 * Matemàtiques . Pi
  Funció final
  Àrea de funció de substitució pública () com a doble
    Retorn radi * radi * Matemàtiques . Pi
  Funció final
Classe final

I així successivament amb les altres figures. D'aquesta manera, si voleu treballar amb una sèrie de figures, no hi ha conflictes de tipus, com en l'exemple següent:

 Disminueix la figura ( 5 ) Com a figura
...
'Suposem que l'usuari introdueix 3 quadrats, un cercle i un hexàgon (s'assumeix la classe d'hexàgons implementada tal com s'ha indicat anteriorment)
'per exemple. Figura (2) = Quadrat nou (4)
'Aquesta instrucció, precisament perquè Square hereta de Figure, no genera errors de compilació
...
Per Cada Fig Com Figura A la figura
  Fig . Draw ()
  Consola . WriteLine ( Fig . Perímetre )
Pròxim

El marmessor, en cada figura que conegui, farà una trucada a la subrutina adequada de la classe a la qual pertany. Així és com passa això.

Recopilació

El polimorfisme es produeix amb una acció combinada de compilador i enllaçador . Contràriament al que passa en la majoria dels casos, el temps d'execució juga un paper molt important en l'execució del codi polimòrfic, ja que no és possible conèixer, en temps de compilació, la classe a la qual pertanyen els objectes instantaniats. El compilador té el paper de preparar el que cal per fer que l’executor decideixi quin mètode invocarà.

Als efectes de la programació polimòrfica no és necessari conèixer el llenguatge ensamblador , però és necessari tenir algunes nocions bàsiques sobre l' adreça per entendre el següent.

Què passa en temps de compilació
el TMV

Quan es compila la classe base, els identifica compilador els mètodes que han estat declarats virtual (paraula clau MustOverride en Visual Basic , virtual en C ++ i el símbol "#" a UML disseny), i construeix un T capaços de V etodes irtual M, indicant les signatures de les funcions a anul·lar . Per tant, aquestes funcions continuen sent "orfes", és a dir, no tenen una adreça per al punt d'entrada.

Quan el compilador tracta les classes derivades, agrupa els mètodes anul·lats en un TMV nou, d’estructura idèntica a la de la classe base, indicant aquesta vegada les adreces del punt d’entrada.

A efectes teòrics, es pot suposar una taula d'aquest tipus:

Figura Quadrat Cercle
 _Dibuix: 0x0000
  _Perimetre: 0x0000
  _Àrea: 0x0000
_Dibuix: 0x3453
  _Perimetre: 0xbc1a
  _Àrea: 0x25bf
_Dibuix: 0x52d0
  _Perimetre: 0x52ab
  _Àrea: 0xaa25

No importa en quin ordre es mapen les funcions, sempre que estiguin en el mateix ordre (al mateix desplaçament ) a la taula. Nota: a nivell de muntatge les TMV no tenen identificadors: són àrees de memòria simples d’una longitud fixa (normalment 32 o 64 bits). Els identificadors s’han inclòs a l’exemple només amb finalitats il·lustratives.

Què passa en temps d'execució
unió dinàmica

Hem vist que el compilador deixa espais en blanc per als mètodes sense mapes. Analitzeu pas a pas, com en un rastre , tot el que passa en temps d'execució. Codi de referència:

 Dim Circle com a figura
Cercle = Nou cercle (3)
Cercle . Draw ()

Suposem que heu instanciat un cercle i voleu dibuixar-lo. La primera afirmació no té molta funcionalitat: simplement reserva espai de pila per a la variable Circle d’una longitud igual a la Figura. A la segona sentència, aquesta pila es realitza realment amb la trucada al constructor. Depenent de l’idioma, el TMV de la figura es sobreescriu amb el de Circle i el valor 3 s’assigna a l’àrea reservada al radi de tipus doble (normalment 64 bits ). En la tercera instrucció, l'executor consulta el TMV de Circle i pren l'adreça de la primera de les funcions assignades. Això es deu al fet que no hi ha identificadors de cap tipus a nivell de muntatge. Un cop recuperada l'adreça, el programa està llest per saltar al punt d'entrada de Disegna.

Polimorfisme paramètric

Un altre mecanisme sovint disponible en llenguatges mecanografiats és el polimorfisme paramètric : en determinats contextos, és possible definir variables amb un tipus parametritzat, que després s’especifica durant l’ús real. Exemples de polimorfisme paramètric són les plantilles C ++ i els genèrics Java.

Articles relacionats

Informàtica Portal de TI : accediu a les entrades de Viquipèdia relacionades amb TI