InicioArticulos y noticiasBases de datosProgramaciónForosInternetServiciosContratacionEmail
Tutorial C#
Introduccion a C#
Programacion con C#
Fundamentos de C#
Operadores
Instrucciones
Estrcuturas de control.
Definición de clases
Creación de objetos
Herencia y métodos virtuales
Polimorfismo
Ocultación de miembros
Miembros de tipo
Encapsulación
Espacios de nombres
Importación de espacios de nombres
Espacio de nombres distribuidos
Variables y tipos de datos
Tablas unidimensionales
Tablas multidimensionales
La clase System.Array
Cadenas de texto
Constantes
Orden de inicialización de variables
Métodos
Métodos externos
Constructores
Destructores
Propiedades
Indizadores
Redefinición de operadores
Delegados y eventos
La clase MulticastDelegate
Llamadas asíncronas
Implementación interna de los delegados
Eventos
Estructuras
Boxing y unboxing
Constructores de estructuras
Enumeraciones
Interfaces
Excepciones
Otras instrucciones
Atributos
Definición de nuevos atributos
Lectura de atributos en tiempo de ejecución
Atributos de compilación
Pseudoatributos
Código inseguro
Definición de punteros
Manipulación de punteros
Operadores relacionados con código inseguro
Fijación de variables apuntadas
Novedades de C# 2.0
Genéricos
Tipos parciales
Iteradores
Mejoras en la manipulación de delegados
Tipos anulables
Modificadores de visibilidad de bloques get y set
Clases estáticas
Referencias a espacios de nombres
Supresión temporal de avisos
Atributos condicionales
Incrustación de tablas en estructuras
Modificaciones en el compilador
También puedes ver ...
Creando cadenas de conexión ConnectionStrings en .net 3.5 o visual Studio 2008 usando SqlConnectionStringBuilder
Migración de WSE a WCF (Web Services de 2005 a 2008)
Generar archivos PDF con C#
TransactionScope - Simplificando el trabajo con transacciones.
LinQ To SQL - Un ejemplo sencillo
Cómo activar Intelisense (autocompletado) en el Web.config
Leer un campo XML de SQL Server 2005 con C#
TripleDES - Un ejemplo practico en C#
Mostrar un GridView dentro de un DataList
String.Format

Afiliados
La Web del programador
MundoProgramacion


 

Polimorfismo

Concepto de polimorfismo

    El polimorfismo es otro de los pilares fundamentales de la programación orientada a objetos. Es la capacidad de almacenar objetos de un determinado tipo en variables de tipos antecesores del primero a costa, claro está, de sólo poderse acceder a través de dicha variable a los miembros comunes a ambos tipos. Sin embargo, las versiones de los métodos virtuales a las que se llamaría a través de esas variables no serían las definidas como miembros del tipo de dichas variables, sino las definidas en el verdadero tipo de los objetos que almacenan.

    A continuación se muestra un ejemplo de cómo una variable de tipo Persona puede usarse para almacenar objetos de tipo Trabajador. En esos casos el campo Sueldo del objeto referenciado por la variable no será accesible, y la versión del método Cumpleaños() a la que se podría llamar a través de la variable de tipo Persona sería la definida en la clase Trabajador, y no la definida en Persona:


using System;
class Persona
{
 // Campo de cada objeto Persona que almacena su nombre
 public string Nombre;     
 // Campo de cada objeto Persona que almacena su edad
 public int Edad;              
 // Campo de cada objeto Persona que almacena su NIF
 public string NIF;            
 
 // Incrementa en uno la edad del objeto Persona
 public virtual void Cumpleaños()
 {
   Console.WriteLine("Incrementada edad de persona");
 }
 
 // Constructor de Persona
 public Persona (string nombre, int edad, string nif)
 {
   Nombre = nombre;
   Edad = edad;
   NIF = nif;
 }
}

class Trabajador: Persona
{
 // Campo de cada objeto Trabajador que almacena cuánto gana
 int Sueldo;
 
 Trabajador(string nombre, int edad, string nif, int sueldo)
     : base(nombre, edad, nif)
 {// Inicializamos cada Trabajador en base al constructor de Persona
   Sueldo = sueldo;
 }
 
 public override Cumpleaños()
 {
   Edad++;
   Console.WriteLine("Incrementada edad de trabajador");
 }
 
 public static void Main()
 {
   Persona p = new Trabajador("Josan", 22, "77588260-Z", 100000);
   p.Cumpleaños();     
   // p.Sueldo++; //ERROR: Sueldo no es miembro de Persona
 }
}

    El mensaje mostrado por pantalla al ejecutar este método confirma lo antes dicho respecto a que la versión de Cumpleaños() a la que se llama, ya que es:

 

 Incrementada edad de trabajador

Métodos genéricos

El polimorfismo es muy útil ya que permite escribir métodos genéricos que puedan recibir parámetros que sean de un determinado tipo o de cualquiera  de sus tipos hijos. Es más, en tanto que cómo se verá en el epígrafe siguiente, en C# todos los tipos derivan implícitamente del tipo System.Object, podemos escribir métodos que admitan parámetros de cualquier tipo sin más que definirlos como métodos que tomen parámetros de tipo System.Object. Por ejemplo:


public void MétodoGenérico(object o)
{
  // Código del método
}

    Nótese que en vez de System.Object se ha escrito object, que es el nombre abreviado incluido en C# para hacer referencia de manera compacta a un tipo tan frecuentemente usado como System.Object.

Determinación de tipo. Operador is

Dentro de una rutina polimórifica que, como la del ejemplo anterior, admita parámetros que puedan ser de cualquier tipo, muchas veces es conveniente poder consultar en el código de la misma cuál es el tipo en concreto del parámetro que se haya pasado al método en cada llamada al mismo. Para ello C# ofrece el operador is, cuya forma sintaxis de uso es:


<expresión> is <nombreTipo>

Este operador devuelve true en caso de que el resultado de evaluar <expresión> sea del tipo cuyo nombre es <nombreTipo> y false en caso contrario[8]. Gracias a ellas podemos escribir métodos genéricos que puedan determinar cuál es el tipo que tienen los parámetros que en cada llamada en concreto se les pasen. O sea, métodos como:


public void MétodoGenérico(object o)
{
 if  (o is int)// Si o es de tipo int (entero)...
               //...Código a ejecutar si el objeto o es de tipo int
 else if (o is string) // Si no, si o es de tipo string (cadena)...
                       //...Código a ejecutar si o es de tipo string
 //... Ídem para otros tipos
}

    El bloque if...else es una instrucción condicional que permite ejecutar un código u otro en función de si la condición indicada entre paréntesis tras el if es cierta (true) o no (false) Esta instrucción se explicará más detalladamente en el Tema 16: Instrucciones

Acceso a la clase base

    Hay determinadas circunstancias en las que cuando redefinamos un determinado método nos interese poder acceder al código de la versión original. Por ejemplo, porque el código redefinido que vayamos a escribir haga lo mismo que el original y además algunas cosas extras. En estos casos se podría pensar que una forma de conseguir esto sería convirtiendo el objeto actual al tipo del método a redefinir y entonces llamar así a ese método, como por ejemplo en el siguiente código:


using System;
class A
{
 public virtual void F()
 {
    Console.WriteLine("A");
 }
}
class B:A
{
 public override void F()
 {
    Console.WriteLine("Antes");
     ((A) this).F();   // (2)
     Console.WriteLine("Después");
 }
 public static void Main()
 {
     B b = new B();
     b.F();
 }
}

Pues bien, si ejecutamos el código anterior veremos que la aplicación nunca termina de ejecutarse y está constantemente mostrando el mensaje Antes por pantalla. Esto se debe a que debido al polimorfismo se ha entrado en un bucle infinito: aunque usemos el operador de conversión para tratar el objeto como si fuese de tipo A, su verdadero tipo sigue siendo B, por lo que la versión de F() a la que se llamará en (2) es a la de B de nuevo, que volverá a llamarse así misma una y otra vez de manera indefinida.

Para solucionar esto, los diseñadores de C# han incluido una palabra reservada llamada base que devuelve una referencia al objeto actual semejante a this pero con la peculiaridad de que los accesos a ella son tratados como si el verdadero tipo fuese el de su clase base. Usando base, podríamos reemplazar el código de la redefinición de F() de ejemplo anterior por:


public override void F()
{
    Console.WriteLine("Antes");
    base.F();
    Console.WriteLine("Después");
}

Si ahora ejecutamos el programa veremos que ahora sí que la versión de F() en B llama a la versión de F() en A, resultando la siguiente salida por pantalla:

 Antes
 A
 Después 

         

A la hora de redefinir métodos abstractos hay que tener cuidado con una cosa: desde el método redefinidor no es posible usar base para hacer referencia a métodos abstractos de la clase padre, aunque sí para hacer referencia a los no abstractos. Por ejemplo:


abstract class A
{
 public abstract void F();
 public void G(){}
}
class B: A
{
 public override void F() 
 {
     base.G();// Correcto
     base.F();// Error, base.F() es abstracto
 }
}

Downcasting

Dado que una variable de un determinado tipo puede estar en realidad almacenando un objeto que sea de algún tipo hijo del tipo de la variable y en ese caso a través de la variable sólo puede accederse a aquellos miembros del verdadero tipo del objeto que sean comunes con miembros del tipo de la variable que referencia al objeto, muchas veces nos va a interesar que una vez que dentro de un método genérico hayamos determinado cuál es el verdadero tipo de un objeto (por ejemplo, con el operador is) podamos tratarlo como tal. En estos casos lo que hay es que hacer una conversión del tipo padre al verdadero tipo del objeto, y a esto se le llama downcasting

Para realizar un downcasting una primera posibilidad es indicar preceder la expresión a convertir del tipo en el que se la desea convertir indicado entre paréntesis. Es decir, siguiendo la siguiente sintaxis:


(
<tipoDestino>) <expresiónAConvertir>

El resultado de este tipo de expresión es el objeto resultante de convertir el resultado de <expresiónAConvertir> a <tipoDestino>. En caso de que la conversión no se pudiese realizar se lanzaría una excepción del tipo predefinido System.InvalidCastException

Otra forma de realizar el downcasting es usando el operador as, que se usa así:


<expresiónAConvertir> as <tipoDestino>

    La principal diferencia de este operador con el anterior es que si ahora la conversión no se pudiese realizar se devolvería null en lugar de lanzarse una excepción. La otra diferencia es que as sólo es aplicable a tipos referencia y sólo a conversiones entre tipos de una misma jerarquía (de padres a hijos o viceversa)

    Los errores al realizar conversiones de este tipo en métodos genéricos se producen cuando el valor pasado a la variable genérica no es ni del tipo indicado en <tipoDestino> ni existe ninguna definición de cómo realizar la conversión a ese tipo (cómo definirla se verá en el Tema 11: Redefinición de operadores)

Clases y métodos sellados

    Una clase sellada es una clase que no puede tener clases hijas, y para definirla basta anteponer el modificador sealed a la definición de una clase normal. Por ejemplo:


sealed class ClaseSellada
{}

    Una utilidad de definir una clase como sellada es que permite que las llamadas a sus métodos virtuales heredados se realicen tan eficientemente como si fuesen no virtuales, pues al no poder existir clases hijas que los redefinan no puede haber polimorfismo y no hay que determinar cuál es la versión correcta del método a la que se ha de llamar.  Nótese que se ha dicho métodos virtuales heredados, pues lo que no se permite es definir miembros virtuales dentro de este tipo de clases, ya que al no poderse heredarse de ellas es algo sin sentido en tanto que nunca podrían redefinirse.

    Ahora bien, hay que tener en cuenta que sellar reduce enormemente su capacidad de reutilización, y eso es algo que el aumento de eficiencia obtenido en las llamadas a sus métodos virtuales no suele compensar. En realidad la principal causa de la inclusión de estas clases en C# es que permiten asegurar que ciertas clases críticas nunca podrán tener clases hijas y sus variables siempre almacenarán objetos del mismo tipo. Por ejemplo, para simplificar el funcionamiento del CLR y los compiladores se ha optado por hacer que todos los tipos de datos básicos excepto System.Object estén sellados.

     Téngase en cuenta que es absurdo definir simultáneamente una clase como abstract y sealed, pues nunca podría accederse a la misma al no poderse crear clases hijas suyas que definan sus métodos abstractos. Por esta razón, el compilador considera erróneo definir una clase con ambos modificadores a la vez.

     Aparte de para sellar clases, también se puede usar sealed como modificador en la redefinición de un método para conseguir que la nueva versión del mismo que se defina deje de ser virtual y se le puedan aplicar las optimizaciones arriba comentadas. Un ejemplo de esto es el siguiente:


class A
{
    public abstract F();
}

class B:A
{
    public sealed override F() // F() deja de ser redefinible
    {}
}


Inicio | Tutorial C# Herencia y métodos virtualesTutorial C#Ocultación de miembros Versión para imprimir Foros de consulta

 
chido por orlando
Respuesta recibida el [29/05/2007 12:03:16]
La informacion que dan es muy buena los felicito por su buen desempeño

 
que chida por beto
Respuesta recibida el [17/08/2007 06:35:22]
gracias por hacer mi tarea

 
felicitaciones por =O
Respuesta recibida el [05/10/2007 04:41:42]
Buen trabajo, comprensible por sobree todo, felicitaciones!

 
los felicito por Nelly Artola
Respuesta recibida el [21/01/2008 10:42:17]
esta muy buena la informacion que brindan... los felicito

 
muchas gracias por Suirik
Respuesta recibida el [24/01/2008 06:15:55]
excelente material

 
Console.WriteLine("Gracias");... por Anónimo
Respuesta recibida el [31/01/2008 04:57:30]
Console.WriteLine("Gracias");

 
Gracias por Yo
Respuesta recibida el [23/02/2008 08:40:27]
Gracias por nada no me sirvio d nada su maldita informacion.
Jaja q se creen los felicito es un excelente material me sirvio de mucho :)

 
messagebox.show por ALFREDYNHO
Respuesta recibida el [10/05/2008 12:06:36]
OOOOOOOUUUUUUUYYYYYYYYEEEEEEEEEEAAAAAAHHHHH

 
MAMENLA por damian
Respuesta recibida el [02/06/2008 02:50:07]
MAMENLA SALAMES!!! JAJAJA!!!

 
nah mentira.. la verdad q muy ... por damian
Respuesta recibida el [02/06/2008 02:51:11]
nah mentira.. la verdad q muy buena la informacion...

 
Muy bueno por raycallao@yahoo.es
Respuesta recibida el [08/08/2008 10:18:38]
Soy un principiante. Encuentro muy buena la informacion, sobre todo cuando explican las diferentes tematicas lo hacen basado en el mismo ejemplo inicial, necesitaria, de ser posible envien toda la informacion del los temas del tutorial a mi correo puedto en campo autor

 
variable sueldo por carlos
Respuesta recibida el [10/11/2008 06:57:30]
En el ejemplo donde se crea un objeto de tipo persona como mostrarias la variable sueldo si no es miembro de persona? porque se debe de poder si le pasaste el parametro sueldo con el valor 100000
porfa porque entonces le pasas el valor de sueldo si no lo puedo mostrar en P


Añadir comentario ... Para preguntar utiliza los foros
Autor:

Título:


Para preguntar utiliza los foros.



Inicio | Tutorial C# Herencia y métodos virtualesTutorial C#Ocultación de miembros Versión para imprimir

Polimorfismo
Autor: José Antonio González Seco
Visitas: 22929 Fecha de publicación: 03/10/2006
José Antonio es experto en tecnologias Microsoft. Imparte cursos y conferencias en congresos sobre C# y .NET en Universidades de toda España (Sevilla, Barcelona, San Sebastián, Valencia, Oviedo, etc.) en representación de grandes empresas como Microsoft.




Visitas: 302 | Comentarios: 0 | Archivo: Articulos
Categorias: ASP.NET|CSS|ASP.NET
Visitas: 137 | Comentarios: 0 | Archivo: Articulos
Categorias: TFS
Visitas: 101 | Comentarios: 5 | Archivo: Articulos
Categorias: TFS
Visitas: 429 | Comentarios: 4 | Archivo: Articulos
Categorias: Transact-SQL|LinQ
Visitas: 1445 | Comentarios: 6 | Archivo: Articulos
Categorias: Visual Basic .NET|C#|ASP.NET|ASP.NET|Programación|ADO.NET
27/09/2008 Navegando ....
Visitas: 238 | Comentarios: 0 | Archivo: Articulos
Categorias: Humor
Visitas: 611 | Comentarios: 0 | Archivo: Articulos
Categorias: Visual Basic .NET|C#|ASP.NET|ASP.NET|Programación|WCF
Visitas: 2570 | Comentarios: 4 | Archivo: Articulos
Categorias: C#
Visitas: 463 | Comentarios: 0 | Archivo: Articulos
Categorias: JavaScript|ASP.NET
Visitas: 1071 | Comentarios: 0 | Archivo: Articulos
Categorias: Windows XP|Linux|Windows Vista

Útimos temas recibidos en los foros ...
Crystal reports XI Release 2 y asp.net por mvargas ... [ASP.NET] 0 21/11/2008
Enviar un email con C# utilizando .Net FrameWork 2.0 con logo... por Moises ... [ASP.NET] 0 21/11/2008
Enviar un email con C# utilizando .Net FrameWork 2.0 por Moises ... [C#] 0 21/11/2008
Cuestión de BFILE. por Megatron ... [ORACLE] 0 21/11/2008
Enviar email por Dol ... [ASP.NET] 5 21/08/2007
*******PREGUNTA********: por T.S.U.En Informatíca ... [Visual Basic 6.0] 5 17/03/2008
Programar tareas en oracle. por Rodrigo ... [ORACLE] 0 21/11/2008
fechas con datatimepicker por peyin ... [Visual Basic .NET] 3 20/11/2008
agregar datos de un gridview a un textbox por jhors ... [ASP.NET] 3 19/09/2007
Select de sql en c# por Stuart ... [C#] 1 20/11/2008
Manual en Español de SQL Navigator for Oracle por Maira ... [ORACLE] 12 30/03/2008
Como mandar mensaje a Celular por Pako ... [C#] 40 13/03/2007

Access CGI JSP ORACLE UNIX
Actualidad HTML/DHTML/XHTML LINUX PHP Visual Basic .NET
ASP ISAPI MS DOS Power Builder Visual Basic 6.0
ASP.NET Java mySQL SQL WIN 98/NT/2000/XP
C# JavaScript Opinion SQL Server

devjoker  Te recomendamos además ...
03/10/2006 Programacion con C#    forma parte de...Tutorial C#
03/10/2006 Polimorfismo    forma parte de...Tutorial C#
01/09/2006 Como encriptar o cifrar cadenas y campos en SQL server 2005 ENCRYPTBYPASSPHRASE y DECRYPTBYPASSPHRASE
19/09/2007 Triggers en Transact SQL    forma parte de...Tutorial de Transact SQL
21/02/2007 BULK COLLECT    forma parte de...Tutorial PL/SQL
09/11/2006 Interfaces    forma parte de...Tutorial C#
31/03/2006 Fundamentos de PL/SQL    forma parte de...Tutorial PL/SQL
10/10/2006 Como conectar a ORACLE con Java
02/09/2007 Procedimientos almacenados en Transact SQL    forma parte de...Tutorial de Transact SQL
14/07/2006 Tablas PL/SQL    forma parte de...Tutorial PL/SQL

 

Encuesta
¿A que perfil te adaptas mejor?
[Ver] [Votar]