Programacion Orientada a Objetos (PPO)

Embed Size (px)

Citation preview

Introduccin:La programacin orientada a objetos (POO) nos permite escribir cdigo menos propenso a fallos adems de permitirnos la reutilizacin de cdigo de forma ms conveniente. En este artculo veremos las caractersticas de la POO desde el punto de vista de los lenguajes de .NET Framework y cmo utilizar los distintos elementos que nos permitirn crear cdigo que sea ms fcil de escribir y mantener.

LA PROGRAMACIN ORIENTADA A OBJETOSEn Todo Programacin existe una seccin denominada Cuadernos de Principiantes donde se estudia algoritmia y estructuras de datos a nivel iniciacin. Est planificado que se estudie a nivel terico la programacin orientada a objetos, por tanto para aquellos que no tengis nocin alguna sobre POO mejor guarda a buen recaudo este nmero de TP y espera a aprender los conceptos tericos necesarios para luego aplicarlos en el marco, nunca mejor dicho, de .NET.

LOS PILARES DE LA POORecordemos que tres son las principales caractersticas de un lenguaje orientado a objetos, es decir, se considera que un lenguaje est totalmente orientado a objetos si es capaz de proveer estas tres caractersticas: Encapsulacin Herencia Polimorfismo

Veamos una pequea descripcin de cada una de ellas y despus las ampliaremos para comprender mejor su significado y cmo puede ayudarnos a crear aplicaciones que aprovechen todas las posibilidades que nos da la POO. La ENCAPSULACIN es la cualidad de unificar los datos y la forma de manipularlos, de esta forma podemos ocultar el funcionamiento de una clase y exponer solo los datos que manipula (mediante propiedades), as como proveer de medios para poder manipular dichos datos (mediante mtodos). De esta forma solo exponemos al mundo exterior la informacin y la forma de manipularla, ocultando los detalles usados para manejar esos datos y, lo que es ms importante, evitando que nadie manipule de una forma no controlada dicha informacin. La HERENCIA es la cualidad de poder crear nuevas clases (o tipos) basadas en otras clases, de forma que la nueva clase obtenga todas las caractersticas de la clase que ha heredado, tanto los datos que contiene como la forma de manipularlos, pudiendo aadir nuevas caractersticas e incluso cambiar el comportamiento de algunas de las incluidas en la clase base, (siempre que as se haya previsto). Mediante la herencia podemos crear de forma fcil una jerarqua

de clases que comparten un mismo comportamiento bsico pero que cada nueva generacin puede tener (y de hecho tiene) un nuevo comportamiento. El POLIMORFISMO es la cualidad de implementar de forma particular algunas de las caractersticas que tienen las clases, de forma que cuando necesitemos usarlas no nos preocupe la implementacin interna que cada una tenga, lo que realmente nos interesa o nos debe importar es que podemos usar esas caractersticas e incluso podamos acceder a ellas de forma annima... o casi.

OTROS CONCEPTOS DE LA POOTal como tendrs oportunidad de ver en los Cuadernos de Principiantes y lo indicado en el cuadro Los pilares de la POO, la POO se basa en tres caractersticas que son comunes a todos los lenguajes orientados a objetos, pero si tenemos esas caractersticas y no sabemos cmo aplicarlas, la verdad es que no nos ser de mucha utilidad. Pero antes de ver algo de cdigo concreto, creo que es importante que aprendamos otros conceptos relacionados tambin con la POO, pero esta vez desde un punto de vista del programador, es decir, vamos a dejar en parte la teora y vamos a ser algo ms prcticos, ya que los siguientes conceptos sern con los que tendremos que "bregar" a diario. Adems nos interesa conocerlos para aprovechar lo que un lenguaje de programacin orientado a objetos nos ofrece, si bien, es posible que, al menos de forma genrica, no todos los lenguajes dispongan de ellos. Por eso, aunque lo que se ha dicho y se diga a continuacin ser vlido para cualquier lenguaje orientado a objetos, lo vamos a enfocar desde el punto de vista de .NET Framework, ms concretamente desde el punto de vista del programador de Visual Basic .NET y C#.

LAS CLASES Y ESTRUCTURASComo hemos estado mencionando, en los lenguajes orientados a objetos, existe el concepto clase. Cuando hablamos de clases, tambin podemos extenderlo a estructuras, de hecho, para los programadores de C++ una clase no es ms que una estructura que se comporta de forma diferente. Una clase es una pieza de cdigo en la que podemos definir una serie de datos y al mismo tiempo unos mtodos (funciones o procedimientos) que nos permitirn acceder a esos datos. Cuando definimos una clase, lo que estamos haciendo es definir una plantilla, a partir de la cual podemos crear objetos en la memoria. Por tanto, la clase es el molde con el cual podemos crear nuevos objetos. Para poder crear algo "tangible" a partir de una clase, tenemos que crear en la memoria un nuevo objeto del tipo de la clase, en estos casos lo que decimos es que instanciamos un nuevo objeto de la clase. A partir de ese momento tendremos algo real con lo que podemos trabajar: una instancia de la clase, es decir, la definicin realizada en la clase se ha convertido en un objeto al que podemos acceder y que podemos empezar a utilizar, dndole nuevos valores a los datos que manipula y usando las funciones que nos permiten manipular dichos datos.

La diferencia principal entre una clase y una estructura es la forma en que se crean los objetos que representan a esas "ideas". Los objetos creados a partir de las clases son objetos por referencia, es decir, si declaramos una variable para manipular ese objeto, lo que tendremos ser una referencia (o puntero) a una direccin de memoria en la que realmente est el objeto. Mientras que los objetos creados a partir de una estructura se almacenan de forma diferente, en lugar de "apuntar" a una direccin de memoria en la que se encuentra el objeto, es como si las variables declaradas como estructuras fuesen realmente el objeto permitindonos hacer ciertas operaciones y manipulaciones que los objetos obtenidos a partir de una clase no pueden realizar de la misma forma. Esto lo veremos despus con ms detalle.

NOTA: Clases En .NET siempre usamos una clase para escribir cualquier tipo de cdigo. Por tanto, hagamos lo que hagamos en .NET Framework, debemos hacerlo dentro de una clase. Esto no quiere decir que siempre tengamos que usar las caractersticas de la POO, ya que si simplemente queremos hacer una aplicacin que muestre un mensaje en la consola, el cdigo no tiene porqu usar la herencia, el polimorfismo o la encapsulacin, simplemente escribimos el cdigo que muestre el mensaje y asunto arreglado, pero lo que si podremos hacer es usar algunas de las "otras" ventajas que nos aporta la programacin orienta a objetos.

INTERFACESCuando hablamos de polimorfismo, ineludiblemente tenemos que hablar de las interfaces, ya que, principalmente, nos posibilita utilizar esta caracterstica de la POO. La pregunta es: qu es una interfaz? Aqu no hablamos de "interfaces de usuario", es decir, lo que se mostrar al usuario de nuestra aplicacin, sino a una clase especial en la que solamente se definen los mtodos y propiedades que una clase que la implemente debe codificar. Las interfaces representan un contrato, de forma que cualquier clase que la implemente debe utilizar los miembros de la interfaz usando la misma forma en que sta la ha descrito: mismo nmero de argumentos, mismo tipo de datos devuelto, etc. Gracias a la implementacin de interfaces podemos crear relaciones entre clases que no estn derivadas de la misma clase base, pero que tengan mtodos comunes, al menos en la forma, aunque no necesariamente en el fondo. Anteriormente usamos el ejemplo del mtodo Guardar, este mtodo se puede definir en una interfaz, las clases que quieran implementar un mtodo Guardar "estandarizado" firmarn un contrato con la interfaz que lo especifica, aunque la forma interna de funcionamiento solo atae al programador de la clase, lo importante es saber que cualquier clase que haya firmado ese contrato tendr que seguir las condiciones impuestas por la interfaz, de esta forma todas las clases tendrn un mtodo Guardar "compatible", aunque, tal como mostramos antes, cmo se realice esa accin de guardar no debe preocuparnos, simplemente nos fiaremos de que se ha implementado adecuadamente para almacenar los datos que la clase manipula.

NOTA: HERENCIA MLTIPLE Y HERENCIA SIMPLE En C++ y algunos otros lenguajes orientados a objetos se permiten la herencia mltiple, es decir, una clase se puede derivar de varias clases a la vez. Los lenguajes de .NET Framework, usan lo que se denomina herencia simple, es decir, una clase solo se puede derivarse directamente de otra clase, si bien se permite implementar mltiples interfaces. Pero debido a cmo funciona la herencia, cualquier clase derivada a partir de otra, heredar indirectamente todas las clases e interfaces que la clase base haya heredado o declarado. Adems, en .NET, todas las clases siempre se derivan de la clase base Object que es la clase que est en la parte superior de la jerarqua de clases.

CONSTRUCTORES Y DESTRUCTORES, EL PUNTO DE INICIO Y FINAL DE LAS CLASESCuando creamos un objeto a partir de una clase, se sigue un proceso, el cual empieza en el momento en que decidimos crear una nueva instancia de dicha clase. En estos casos, el compilador utiliza lo que se llama el constructor de la clase. Siempre que se crea un nuevo objeto en la memoria est involucrado el constructor de la clase. Los constructores son procedimientos especiales (funciones que no devuelven un valor) en los que podemos escribir toda la lgica que debe usarse para la correcta creacin del objeto. Por ejemplo, podemos inicializar las variables usadas, podemos asignarle algunos valores predeterminados, etc. De igual forma, cuando un objeto ya no se necesita ms, se destruye mediante una llamada al destructor de la clase. En .NET la destruccin de los objetos suele hacerse de forma automatizada, es decir, a diferencia de lo que ocurre en otros entornos de programacin, no es necesario destruir explcitamente un objeto para eliminarlo de la memoria, esa gestin de limpieza de objetos la realiza el recolector de basura (Garbage Collector, GC) de .NET, el cual decide cuando un objeto no se necesita ms y en ese caso lo elimina dejando libre la memoria utilizada para otros menesteres.

SOBRECARGA (OVERLOAD)Una de las caractersticas que tambin nos ofrece los lenguajes orientados a objetos es la posibilidad de definir varias funciones de las clases con un mismo nombre, de esta forma, podremos crear versiones diferentes, por ejemplo para que reciban argumentos de distintos tipos sin necesidad de cambiarle el nombre. Supongamos que queremos hacer una funcin que realice cualquier tipo de operacin sobre dos valores numricos, sera lgico pensar que si esos valores son de tipo entero, el resultado que devuelva la funcin tambin debera ser de tipo entero, en caso de que los valores a usar en la operacin son de tipo flotante, el resultado podra devolverlo de ese mismo tipo.

En los lenguajes no orientado a objetos, tendramos que crear dos funciones con nombres diferentes, por ejemplo: sumaInt y sumaFloat. Pero la sobrecarga nos permite crear dos funciones que se llamen suma y el compilador utilizar la adecuada segn el tipo de datos que pasemos como argumentos. El nico requisito para poder crear sobrecargas de mtodos es que las diferentes versiones se diferencien en los argumentos, ya sea porque sean de diferentes tipos de datos o porque el nmero de argumentos usados sea diferente, de esa forma el compilador no tendr ningn problema en saber cual debe usar en cada ocasin. La sobrecarga la podemos aplicar tanto a los constructores como a cualquier otro mtodo de la clase.

NOTA: Sobrecarga No existir la posibilidad de crear mtodos sobrecargados si solamente se diferencian en el tipo de datos devuelto, ya que en esos casos el compilador no podr decidir correctamente qu mtodo debe utilizar.

LOS MIEMBROS DE LAS CLASES: CAMPOS, PROPIEDADES Y MTODOSComo hemos comentado, las clases manejan datos y proveen de funciones para acceder a esos datos. Para ser precisos, los datos se mantienen o almacenan internamente en los campos declarados en las clases. Los campos no son otra cosa que variables declaradas en la clase, habitualmente declaradas de forma privada. Por qu declaradas de forma privada? Precisamente para seguir o cumplir la caracterstica de encapsulacin de la POO, es decir, los datos no deben exponerse de forma directa. Si queremos exponer los datos, podemos usar las propiedades. Las propiedades son funciones especiales que nos permiten acceder a esos datos, aunque para ser ms precisos, las propiedades realmente representan a los datos que una clase contiene, al menos de forma pblica. De esa forma podemos "controlar" la forma en que se leen o asignan esos datos, ya que las propiedades realmente son funciones en las que podemos escribir cdigo para controlar los valores asignados o ledos. Los mtodos nos permitirn realizar acciones sobre los datos, por ejemplo devolver un rango de valores o simplemente una representacin amigable de la informacin contenida. Debido a que algunas veces los mtodos devolvern algo y otras no, podemos usar tanto funciones que devuelvan o no un valor.

NOTA: Mtodos En C# los mtodos siempre son funciones, que devolvern un tipo concreto o el valor especial void, que se usa para indicar que una funcin no devolver ningn valor. En Visual Basic .NET existen dos tipos de mtodos distintos, las funciones (Function) que siempre devuelven un valor y los procedimientos (Sub) que no devuelven ningn valor.

Adems de los campos, mtodos y propiedades, las clases tienen otros miembros como los eventos y las enumeraciones. stos nos permitirn recibir notificaciones de cuando algo ocurra (eventos) o declarar ciertos valores constantes que podemos usar para restringir algunos valores asignados a las propiedades o que nos permitan seleccionar de forma coherente la informacin que queremos obtener (enumeraciones).

EL MBITO DE LOS MIEMBROS DE LAS CLASESLas buenas formas de trabajar con las clases nos indican que los campos deberan ser privados, con idea de que no estn accesibles de forma externa. Por supuesto tambin podemos definir otros miembros de las clases de forma privada, esto es til cuando la funcionalidad es para uso exclusivo de otros miembros de la clase. Pero cuando queremos exponer la funcionalidad fuera de la clase podemos hacerla de varias formas, aqu es donde entran en juego el mbito de los miembros de las clases. El mbito lo aplicamos para permitir el acceso desde cualquier cdigo fuera de la clase o para restringir ese acceso. Dependiendo de cmo queramos que se acceda a los miembros de la clase podemos usar distintos modificadores de mbito. Veamos los que podemos usar y cuando y porqu usarlos. La instruccin entre parntesis ser la que tendremos que usar en C#. Private (private). Para uso privado. Cuando declaramos un miembro como privado slo lo podremos acceder desde la propia clase. Este es el ms restrictivo y el que se recomienda para los campos y las funciones de uso interno. Protected (protected). Uso protegido. Los elementos declarados como protegidos slo estarn accesibles, adems de en la propia clase, por cualquier clase derivada. Friend (internal). Para uso dentro de la propia aplicacin. Cuando declaramos un miembro con este modificador, solo podremos acceder a l desde la propia clase o desde cualquier cdigo que se encuentre en el mismo ensamblado (proyecto). Protected Friend (protected internal). Una mezcla de Protected y Friend, es decir solo accesible desde las clases derivadas o desde el mismo proyecto. Public (public). Este modificador de mbito nos permite exponer pblicamente cualquier miembro de la clase, de forma que no haya restricciones para acceder a l.

NOTA: mbito Los miembros de una clase los podemos declarar sin especificar el mbito, dependiendo del lenguaje de programacin que usemos se aplicar un modificador de mbito u otro. En C#, si no indicamos el mbito, las declaraciones se consideran privadas, mientras que en Visual Basic .NET el mbito predeterminado es Friend.

MIEMBROS VIRTUALES, NO REEMPLAZABLES Y ABSTRACTOSPara ir terminando la parte "terica" sobre la programacin orientada a objetos, veamos cmo podemos darle un significado distinto a los miembros de una clase, dependiendo de cmo queramos que se comporten y por extensin cmo podemos utilizarlos tanto en la propia clase como en las clases derivadas. Como hemos comentado, cuando una clase hereda a otra podemos modificar el comportamiento de los miembros heredados, pero estos solamente se podrn modificar si la clase base as lo contempla o lo permite. De forma predeterminada, al menos en .NET, cuando declaramos un mtodo o una propiedad en una clase, solo podremos acceder a l desde una instancia creada (un objeto) en memoria, desde donde podemos usarlos depender del mbito que le hayamos aplicado. De igual forma, el que una clase que se base en otra, pueda crear su propia versin de ese mtodo o propiedad depender de que la clase base lo haya declarado como virtual (Overridable en VB .NET). Los mtodos virtuales sern los que podamos sobrescribir en las clases derivadas, de forma que podamos crear nuestras propias versiones. En .NET los miembros de una clase no son virtuales de forma predeterminada. Por tanto, si queremos que la clase derivada pueda crear su propia versin de un mtodo, debemos declararlo como virtual o "redefinible". Si en una clase base hemos definido un mtodo virtual, pero posteriormente queremos que no se pueda seguir redefiniendo en otras clases derivadas, debemos indicarlo usando el modificador NotOverridable, el cual se usar junto con Overrides, ya que sobrescribe un miembro de la clase base y como adems lo queremos marcar como no virtual, debemos usar las dos instrucciones: Overrides NotOverridable, (en C# se indicar con override sealed). Pero tambin se nos puede presentar el caso contrario, en el que queremos que un mtodo forzosamente haya que redefinirlo en las clases derivadas, en esos casos la clase base que lo define no incluye ninguna implementacin, es decir, el mtodo no contiene cdigo ejecutable, solo la definicin, (como ocurre con las interfaces). Se dice que estos mtodos son abstractos porque solo se ha definido en la forma y no se ha implementado ningn cdigo ejecutable. En Visual Basic se definen usando el modificador MustOverride (asbtract en C#). Estos mtodos abstractos solo se pueden declarar en clases abstractas (MustInherit en Visual Basic, abstract en C#) y por la necesidad de tener que redefinirlos, son implcitamente virtuales. Las instrucciones o modificadores que nos permiten crear estos tipos de miembros son:

Overridable (virtual). Los miembros virtuales son los que las clases derivadas puedes sobrescribir para crear su propia versin. Para indicar en una clase derivada que estamos sobrescribiendo dicho elemento, usaremos Overrides (override en C#). NotOverridable (sealed). Los miembros virtuales heredados se pueden marcar como no virtuales, (las siguientes clases derivadas no podrn sobrescribirlos), usando esta instruccin a continuacin de Overrides (override). MustOverride (abstract). Un mtodo que se debe reemplazar en la clase derivada y que solo se define en la clase base sin ningn cdigo ejecutable. Los mtodos abstractos son virtuales por defecto y solo se pueden declarar en clases abstractas.

MIEMBROS DE INSTANCIAS Y COMPARTIDOSEn todos estos casos, los miembros de la clase siempre son miembros de instancia, es decir, solo existen en la memoria cuando se crea un nuevo objeto (se crea una nueva instancia). Pero es posible que nos interese crear miembros compartidos, es decir, miembros que pertenecen a la propia clase, no a ninguna instancia en particular. Dndonos la oportunidad de poder acceder siempre a ellos, independientemente de que hayamos creado o no un nuevo objeto en la memoria. En estos casos decimos que creamos miembros compartidos (estticos en el argot de C#/C++), esta diferencia de "nomenclatura" dependiendo del lenguaje de programacin, es porque para definir un miembro perteneciente a la clase y no a una instancia en particular, usaremos en Visual Basic la instruccin Shared (compartido), mientras que en C# se usar la instruccin static (esttico). Resumiendo, Shared (static), declara un miembro compartido, los miembros compartidos no pertenecen a ninguna instancia en particular y solamente pueden acceder a campos u otros miembros tambin compartidos. Desde los miembros de instancia podemos acceder tanto a miembros compartidos como de instancia.

NOTA: STATIC En Visual Basic existe tambin la instruccin Static, (que no tiene equivalencia en C#), en este caso se utiliza con variables declaradas en un procedimiento y sirven para indicar que esa variable debe mantener el valor entre distintas llamadas a dicho procedimiento, a diferencia del resto de variables que solo existen mientras se ejecuta el cdigo del procedimiento y cuyos valores se pierden al finaliza la ejecucin del mismo.

CLASES ABSTRACTAS Y SELLADASDe igual forma que podemos modificar el comportamiento de los miembros de una clase, tambin podemos cambiar el comportamiento predeterminado de las clases. Como hemos comentado, las clases de .NET pueden usarse para crear nuevas clases derivadas de ellas, esta es la funcionalidad predeterminada, pero no obligatoria, es decir, si queremos podemos usar una clase por si misma o como base de otras. Pero tambin podemos hacer que una clase solamente se use como clase base de otras, pero no se puedan usar para crear nuevas instancias en memoria, este es el caso de las clases abstractas. Una clase abstracta puede contener miembros abstractos, miembros normales o virtuales. Para indicar que una clase es abstracta, se usa el modificador MustInherit en Visual Basic o abstract en C#. La contrapartida de las clases abstractas son las clases selladas o clases que no se pueden usar como clases base, en estos casos las clases las definiremos como NotInheritable en Visual Basic o sealed en C#. Como es lgico, las clases no heredables se pueden usar en ocasiones en las que no nos interese que nadie cambie el comportamiento que tiene, por tanto no se podrn declarar miembros virtuales ni abstractos, ya que no tendra ningn sentido. Las estructuras siempre son "clases selladas", (aunque no se use un modificador para indicarlo), por tanto, no podemos usarlas como base de otras.

ConclusionesEn la segunda parte de esta serie dedicada a la programacin orientada a objetos veremos cmo poner en prctica todo lo que hemos comentado, adems de ver otras peculiaridades de la POO, tales como la definicin de interfaces y cmo implementarlas, ocasin que tambin aprovecharemos para ver de forma prctica cmo usar el polimorfismo y la herencia en los lenguajes de .NET.

Programacin Orientada a Objetos en .NET (2) Conceptos prcticosPublicado el 13/Dic/2006 Actualizado el 13/Dic/2006 Autor: Guillermo 'guille' SomImportante: Este artculo est registrado por Iberprensa (Studio Press) y est prohibida la reproduccin total o parcial incluso indicando la procedencia.

En esta ocasin veremos con ejemplos prcticos cmo utilizar las caractersticas de la POO usando lenguajes de .NET, de forma que tengamos claro cmo usar la herencia, el polimorfismo y la encapsulacin, pero con cdigo. Versin originalmente publicada en Todo Programacin nmero 7 (Oct 2004)

Introduccin:En el artculo anterior vimos algunos conceptos tericos de la POO (Programacin Orientada a Objetos) desde el punto de vista de los lenguajes de .NET Framework, en esta ocasin veremos con ejemplos prcticos cmo utilizar las caractersticas de la POO en Visual Basic .NET, (en el ZIP se incluye tambin el cdigo para C#), de forma que tengamos claro cmo usar la herencia, el polimorfismo y la encapsulacin, pero con cdigo.

VISUAL BASIC .NET Y LA POOTal como comentamos en el artculo anterior, uno de los pilares de la POO es la herencia. Mediante la herencia podemos definir clases totalmente operativas y crear nuevas clases basadas en ellas de forma que hereden toda la funcionalidad de la clase base y nos permita ampliarla. Por tanto, vamos a empezar viendo cmo definir una clase y cmo aplicar en Visual Basic .NET el resto de conceptos relacionados con la programacin orientada a objetos.

Nota: Este artculo se public en Octubre de 2004, y por tanto todo lo aqu explicado est relacionado con la versin 1.1 de .NET Framework. La versin de .NET Framework que hay actualmente (a la hora de escribir esta nota) es la 3.0, (que en el fondo es la misma que la 2.0), y se han introducido ciertos cambios o mejoras, pero bsicamente lo aqu explicado sigue siendo tan vlido ahora como hace dos aos.

DEFINIR CLASES EN VISUAL BASIC .NETAntes de poder usar las caractersticas de la POO tendremos primero que aprender a declarar una clase. La declaracin de una clase se define usando la instruccin Class seguida del nombre de la clase y termina

usando las instrucciones End Class. Dentro de ese bloque definiremos los campos, propiedades y mtodos que queramos que tenga la clase.

NOTA: En Visual Basic .NET la definicin de una clase se puede hacer en cualquier fichero de cdigo (con extensin .vb), aunque no es obligatorio hacerlo en un fichero independiente como ocurra con las versiones anteriores, es recomendable hacerlo, para que nos resulte ms fcil de mantener.

Public Class A Private _prop2 As Integer Private _prop1 As String ' Public Property Prop1() As String Get Return _prop1 End Get Set(ByVal value As String) If value "" Then _prop1 = value End If End Set End Property Public Property Prop2() As Integer Get Return _prop2 End Get Set(ByVal value As Integer) _prop2 = value End Set End Property ' Public Sub Mostrar() Console.WriteLine("{0}, {1}", _prop1, _prop2) End Sub End Class

Listado 1 Tal como podemos ver en el listado 1, tenemos una clase llamada A que define dos campos, dos propiedades y

un mtodo. Los dos campos, declarados como privados, se usan para mantener "internamente" la informacin que se expone mediante las dos propiedades pblicas, de esta forma protegemos los datos y esta sera una forma de encapsular la informacin. De las dos propiedades definidas para acceder a esos datos, solo la propiedad Prop1 hace una comprobacin de que no se asigne una cadena vaca al campo que mantiene internamente la informacin, aunque en este ejemplo por su simplicidad no hacemos ms comprobaciones, en una clase algo ms compleja, se podran realizar otras comprobaciones, por ejemplo si el valor a almacenar es una cuenta de email, podramos comprobar que es una cadena correctamente formada. Las propiedades suelen definir dos bloques de cdigo, uno, el bloque Get se utiliza cuando queremos acceder al valor devuelto por la propiedad, el otro es el bloque Set, el cual se utilizar cuando asignemos un valor a la propiedad. El mtodo Mostrar se usar para mostrar el contenido de las dos propiedades por la consola y est definido como Sub (void en C#) porque no devuelve ningn valor.

SOBRESCRIBIR MIEMBROS HEREDADOSTal como comentamos en el artculo anterior, todas las clases de .NET se derivan directa o indirectamente de la clase Object. La clase definida en el listado 1 tambin se deriva de Object aunque no se indique expresamente. La clase base de todas las clases de .NET tiene un mtodo que se utiliza para recuperar informacin, (en formato cadena), del contenido de la clase: el mtodo ToString. Cada clase puede crear su propia versin del mtodo ToString para que devuelva una representacin adecuada, por ejemplo los tipos numricos devuelven una cadena que representa al nmero que contiene. En nuestra clase podemos redefinirlo para que nos devuelva el contenido de los dos datos que la clase mantiene:Public Overrides Function ToString() As String Return String.Format("{0}, {1}", _prop1, _prop2) End Function

Para indicarle al compilador que estamos redefiniendo un mtodo ya existente, lo indicamos con la instruccin Overrides (override en C#). Debido a que ahora nuestra clase tiene una nueva versin de este mtodo, cualquier clase que se derive de ella tambin heredar la nueva implementacin del mtodo ToString.

USAR LA HERENCIA EN VISUAL BASIC .NETLa clase que hemos definido en el listado 1 no indicaba de ninguna forma que se deriva de la clase Object, este es un caso excepcional, ya que todas las clases de .NET se derivan de forma "automtica" de la clase Object. Para indicar en Visual Basic .NET que una clase se deriva de otra, debemos usar la instruccin (o palabra clave) Inherits seguida de la clase que queremos usar como base. Esa instruccin tiene que indicarse al principio de la declaracin de la clase, antes que cualquier otra instruccin, con excepcin de los comentarios.

Para crear una clase que se derive de la clase A definida en el listado 1, tendramos que hacer lo siguiente:Public Class B Inherits A End Class

Tal como podemos comprobar, la clase B no define ningn mtodo ni propiedad, pero realmente si que tiene mtodos y propiedades: todos los que tenga la clase A (adems de los de la clase Object). Para comprobarlo podemos definir una variable del tipo de la clase B y comprobaremos que esta clase tiene los mismos miembros que la clase A, tal como se muestra en el listado 2.Sub Main() Dim objB As New B

objB.Prop1 = "guille" objB.Prop2 = 47

objB.Mostrar() Console.WriteLine("{0}", objB.ToString) End Sub

Listado 2

OCULTAR MIEMBROS HEREDADOSTodo funciona como esperbamos, aunque hay un pequeo problema, si quisiramos modificar el comportamiento de los miembros heredados por la clase B, no podramos hacerlo. La razn es bien simple: la clase A no ha definido los miembros como virtuales (o reemplazables). Por tanto no se pueden crear nuevas versiones de los mismos en la clase B, o casi... Realmente la clase B si que puede definir nuevas versiones de los miembros que tiene la clase A, al menos puede crear mtodos y propiedades que tengan el mismo nombre, por ejemplo:Public Sub Mostrar() Console.WriteLine("Mostrar en la clase B: {0}, {1}", Prop1, Prop2) End Sub

Esto es totalmente correcto, al menos en el sentido de que no produce ningn error; lo ms que producir esa declaracin es una advertencia del compilador indicndonos que ese mtodo entra en conflicto con el definido en la clase base A, tal como podemos comprobar en la figura 1.

Figura 1. Advertencia de ocultacin Esa advertencia nos informa que deberamos indicar que la declaracin "oculta" a la definida en la clase A y por tanto deberamos usar la instruccin Shadows (new en C#). Aunque usemos Shadows, el problema real sigue existiendo: el mtodo declarado en la clase B oculta al declarado (y heredado) en la clase A. Si despus de definir este mtodo de la clase B volvemos a ejecutar el cdigo del listado 2, comprobaremos que se utiliza el nuevo mtodo. Posiblemente el lector pensar que eso es lo que queramos conseguir: tener nuestra propia versin del mtodo Mostrar. Es ms, si definimos una nueva clase que se derive de B podemos comprobar que realmente es ese mtodo el que se hereda por la nueva clase. En el listado 3 podemos ver la definicin de la clase C y el cdigo para comprobar lo que mostrara:Public Class C Inherits B End Class

Sub Main() Dim objC As New C

objC.Prop1 = "guille" objC.Prop2 = 47

objC.Mostrar() Console.WriteLine("{0}", objC.ToString) End Sub

Listado 3 Y lo que imprime es exactamente lo mismo que usando la clase B. Por tanto, el objetivo est conseguido, es decir, la clase B ha "redefinido" un mtodo de la clase A y esa nueva versin es la que se usar a partir de ese momento por las clases que se basen en la clase B. Aparentemente as es. Al menos si lo tomamos al pie de la letra. El nico problema es que acabamos de romper una de las cualidades de la programacin orientada a objetos:

el polimorfismo. Esta nueva definicin del mtodo Mostrar ya no tiene nada que ver con la definida por la clase A y por tanto no existe ninguna relacin "polimrfica" entre ambos mtodos. Para ser ms precisos, tanto la clase B como la clase C tienen dos definiciones del mtodo Mostrar: el inicialmente heredado de la clase A y el nuevo definido por la clase B, aunque siempre prevalecer el definido expresamente en la clase derivada frente al heredado de la clase base. Si pudisemos ver el objeto creado en la memoria a partir de la clase B (e incluso de la clase C), nos daramos cuenta de que realmente est dividido en tres partes, tal como se muestra en la figura 2: 1. La parte heredada de la clase Object 2. La parte heredada de la clase A 3. Las definiciones propias de la clase B

Figura 2. Objeto B en memoria El mtodo ToString definido en Object ha sido reemplazado o, para que lo comprendamos mejor, sustituido por el redefinido en la clase A, pero el mtodo Mostrar de la clase A an existe, lo que ocurre es que ha sido ocultado por el que se ha definido en la clase B. Para demostrar que es as, que existen dos mtodos Mostrar en la memoria, podemos utilizar el polimorfismo para "extraer" el mtodo Mostrar que est oculto. Para ello tendremos que declarar una variable del tipo de la clase A y decirle que extraiga del objeto B la parte que le corresponde: solo la parte definida en la clase A. Esto se consigue de una forma muy simple: asignando a una variable del tipo A el contenido de la variable que

apunta al objeto B:Dim objA As A objA = objB

A partir de este momento el objeto B est siendo referenciado por el objeto A, pero, y esto es importante, solo la parte que A conoce, es decir, la variable objA solamente podr acceder al "trozo" del objeto B que se deriv de la clase A. Por tanto, si llamamos al mtodo Mostrar de la variable objA, accederemos al mtodo Mostrar que el objeto B contiene porque la consigui al derivarse de A. S, esto es algo complicado y que no es fcil de comprender, pero es importante intentar asimilarlo, ya que es muy probable que lo necesitemos en nuestros proyectos, sobre todo si sabemos que se puede hacer. Adems de que esta sera la nica forma que tenemos de acceder a ese mtodo "oculto", ya que cualquier intento de acceder al mtodo Mostrar mediante un objeto del tipo B, siempre acceder al definido en la propia clase B y que oculta al heredado de la clase A.

NOTA: Cuando declaramos una variable y la instanciamos, (creando un nuevo objeto a partir de una clase), dicha variable simplemente tiene una referencia al objeto creado en la memoria, (la variable simplemente tiene un puntero al objeto real), por tanto, ese objeto existe y puede ser referenciado por otras variables, aunque esas otras variables deben ser de tipos "incluidos" en la clase usada para crear dicho objeto. Al instanciar un nuevo objeto del tipo B, (tal como se muestra en la figura 2), podemos acceder a l mediante variables de tipo Object, de tipo A y, por supuesto, de tipo B.

INDICAR LOS MIEMBROS VIRTUALESComo hemos comprobado, si queremos que los miembros de nuestra clase se puedan redefinir en clases derivadas, debemos indicarlo de forma expresa. Para que esto sea as, utilizaremos la instruccin Overridable (virtual en C#). De esta forma le indicaremos al compilador que el mtodo se puede redefinir, es decir, que en la clase derivada se puede crear una nueva versin "personalizada" de dicho miembro. Con esto logramos que en sucesivas derivaciones de la clase solamente exista un mismo miembro polimrfico. La ventaja principal es que si en otra clase decidimos crear una nueva versin de, por ejemplo, un mtodo, cuando se cree un objeto en la memoria, solo existir ese mtodo, no varios mtodos con el mismo nombre, pero sin ninguna relacin entre ellos, exceptuando el hecho de que se llamen de la misma forma. Tal como vimos en la seccin SOBRESCRIBIR MIEMBROS HEREDADOS, tendremos que usar la instruccin Overrides (override en C#), para indicar que nuestra intencin es crear una versin propia de uno de los miembros heredados. Pero no solo basta con usar esa instruccin, ya que si queremos redefinir un miembro existente en alguna de las clases que hemos heredado, la "firma" de nuestra versin debe ser la misma que el original. Es decir, si es un mtodo que devuelve una cadena y no recibe parmetros, debemos "respetar" esas mismas caractersticas, porque de lo que se trata es de cumplir con un contrato, dicho contrato estipula que tipo de miembro es, (un mtodo o una propiedad), que tipo de datos devuelve, si recibe o no parmetros y en caso de que los reciba de

que tipo deben ser. Todo esto es para garantizar que esos miembros se puedan usar de forma independiente de la clase en el que se ha declarado, con idea de que podamos acceder a ellos mediante objetos de las clases que se han usado para crear la nueva, (las clases de las que se deriva la clase que sobrescribe el mtodo). Por ejemplo, si el mtodo Mostrar definido en la clase A se hubiese declarado como virtual, (Overridable), y en la clase B lo hubisemos redefinido usando la instruccin Overrides, podramos acceder a dicho mtodo (de un objeto creado a partir de la clase B) usando tanto una variable de la clase A como una de la clase B; ya que en la memoria solamente existir un mtodo llamado Mostrar. A diferencia de lo que ocurra antes (al no declararlo como virtual), que realmente existan dos mtodos Mostrar.

DEFINIENDO INTERFACESUna interfaz realmente es la definicin de los miembros pblicos de una clase. Pero en los lenguajes de programacin de .NET tambin podemos definir clases especiales que simplemente definan cmo deben ser los miembros que una clase implemente. Es decir que caractersticas deben tener. De esta forma podemos garantizar que si varias clases implementan los miembros definidos en una interfaz, podemos usarlos de manera annima, es decir, sin necesidad de saber si estamos usando un objeto de una clase o de otra, ya que si ambas clases implementan la interfaz, tendremos la certeza de que dichas clases tienen los miembros definidos en dicha interfaz. Una interfaz representa un contrato, si una clase implementa una interfaz, est suscribiendo dicho contrato, es ms, est obligada a cumplirlo, por tanto, la clase tendr que definir todos los miembros que la interfaz contenga. Antes de ver cmo usar las interfaces en nuestras clases, veamos cmo definir una interfaz.Public Interface IPrueba2 Property Prop1() As String Sub Mostrar() End Interface

En este caso hemos definido una interfaz llamada IPrueba2 (por convencin los nombres de las interfaces siempre empiezan con la letra I mayscula), en la que se define una propiedad y un mtodo. Los miembros de las interfaces siempre son pblicos y no deben implementar cdigo, solamente la definicin propiamente dicha.

UTILIZAR INTERFACES EN LAS CLASESCualquier clase que quiera disponer de los miembros definidos en la interfaz debe indicarlo de forma expresa, ya que no solo es suficiente con definir los miembros con nombres y caractersticas similares. Para "implementar" en una clase los miembros definidos en una interfaz tendremos que usar la instruccin Implements seguida del nombre de la interfaz. Adems tendremos que definir los mtodos y propiedades que dicha interfaz contiene, aunque en Visual Basic adems hay que indicarlo expresamente, de forma que se sepa con seguridad de que cada uno de esos miembros equivale a los definidos en la interfaz. En el listado 4 vemos cmo definir una clase que utilice la interfaz que acabamos de ver en la seccin anterior.

Public Class Prueba2 Implements IPrueba2

Public Sub Mostrar() _ Implements IPrueba2.Mostrar ' nuestra version del mtodo Mostrar End Sub

Public Property Prop1() As String _ Implements IPrueba2.Prop1 Get ' el cdigo que devuelve ' el valor de la propiedad End Get Set(ByVal value As String) ' el cdigo que asigna ' el valor de la propiedad End Set End Property End Class

Listado 4 El mtodo y las dos propiedades deben tener el mismo nombre y parmetros (si los hubiera) que los definidos en la interfaz. Cuando trabajamos con Visual Basic adems debemos indicar expresamente que dicho mtodo o propiedad est "ligado" con el definido en la interfaz, cuando trabajamos con C# no es necesario indicarlo. La ventaja de esta "redundancia" de VB es que podemos dar un nombre diferente al miembro implementado, pero "internamente" el compilador sabr que nos estamos refiriendo al que implementa la interfaz. Tal como podemos ver en el listado 5, a pesar de que en la clase Prueba2B al mtodo le hemos dado otro nombre, realmente est haciendo referencia al que se ha declarado en la interfaz.Public Class Prueba2B Implements IPrueba2

Public Sub OtroNombre() _ Implements IPrueba2.Mostrar Console.WriteLine("Este es el mtodo Mostrar de la clase Prueba2B") End Sub

Public Property Prop1() As String _ Implements IPrueba2.Prop1 Get Return "Prop1 de la clase prueba2B" End Get Set(ByVal value As String) ' End Set End Property End Class

Dim p2 As New Prueba2 Dim p2b As New Prueba2B Dim i As IPrueba2 ' i = p2 i.Mostrar() ' i = p2b i.Mostrar()

Listado 5

POLIMORFISMO USANDO CLASES E INTERFACESEn los ejemplos mostrados ya hemos visto cmo usar el polimorfismo tanto a travs de variables incluidas en las clases como con interfaces que dichas clases implementan; vamos a detallar un poco ms, ya que esta es una de las caractersticas ms usadas en .NET, por la sencilla razn de que muchas clases de .NET Framework implementan interfaces de forma que podamos acceder a los miembros implementados por medio de variables del tipo de dichas interfaces. Es ms, muchas de las clases de .NET adems permiten que demos nueva funcionalidad a nuestras propias clases si implementamos ciertas interfaces. Por ejemplo, si queremos que nuestra clase sea "clasificable", es decir, que se pueda usar en una coleccin que clasifique los elementos que contiene, nuestra clase debe implementar la interfaz IComparable. Si definimos una clase en la que queremos que el mtodo ToString acte de forma que podamos especificar ciertos formatos a la hora de mostrar el contenido, nuestra clase debe implementar IFormattable. Que queremos que nuestra clase acte como una coleccin, en la que se pueda enumerar o recorrer el contenido de la misma, debemos implementar la interfaz IEnumerable. Pero esas interfaces propias del .NET Framework lo que harn ser darle una nueva funcionalidad a nuestras clases, por tanto, lo importante es saber de que forma actan los objetos creados en la memoria. Tal como hemos comentado antes, solo existe un objeto en la memoria y cuando accedemos a l lo podemos hacer bien usando alguna de las clases de las que se deriva o bien mediante alguna de las interfaces que

implementa. Cuando accedemos a dicho objeto mediante algunas de estas clases o interfaces simplemente estamos accediendo a la parte "conocida" por dicho tipo. En el cdigo del listado 4 y 5 la interfaz IPrueba2 "sabe" cmo acceder al mtodo Mostrar y a la propiedad Prop1, independientemente del objeto que la haya implementado, por tanto si una clase implementa dicha interfaz podemos acceder a esos miembros mediante una variable del tipo IPrueba2, tal como se demuestra en el listado 5 en el que accedemos al mtodo Mostrar definido en la interfaz e implementado por las dos clases.

USAR EL POLIMORFISMO PARA ACCEDER A ELEMENTOS DIFERENTES DE UN ARRAY O COLECCINUna de las utilidades del polimorfismo (de clases o interfaces) es que podemos crear arrays de variables de un tipo "bsico" y en ese array incluir objetos que si bien son distintos, en el fondo tienen como parte componente la clase de la que se ha declarado el array. El ejemplo ms bsico y vlido tanto para las clases declaradas en el propio .NET Framework como las declaradas por nosotros mismos, es crear un array de tipo Object, dicho array podr contener objetos de cualquier tipo (incluso tipos como nmeros enteros, cadenas, etc.), y posteriormente poder acceder a cualquiera de los elementos mediante un objeto del tipo Object, en cuyo caso solo podremos acceder a los mtodos que Object implementa o bien mediante objetos de un tipo en particular, en cuyo caso nos veremos obligados a hacer una conversin desde el tipo contenido en el array (Object) al tipo particular que nos interese. En el listado 6 podemos ver un ejemplo en el que se crea un array de tipo Object pero que se almacenan tanto objetos del tipo clase A, clase B, IPrueba2, Integer y String.Dim a(6) As Object ' Dim a1 As New A a1.Prop1 = "Objeto A" Dim b1 As New B b1.Prop1 = "Objeto B" Dim c1 As New C c1.Prop1 = "Objeto C" ' a(0) = a1 a(1) = b1 a(2) = c1 a(3) = New Prueba2 a(4) = New Prueba2B a(5) = 15 a(6) = "Hola" ' Dim i As Integer Console.Write("Usando el mtodo ToString")

Console.WriteLine(" de los objetos contenidos") For i = 0 To a.Length - 1 Console.WriteLine("a({0}) = {1}", i, a(i).ToString()) Next ' Console.WriteLine() ' Console.WriteLine("Usando un Object") Dim o As Object For Each o In a Console.WriteLine("o.ToString = {0}", o.ToString()) Next ' Console.WriteLine() ' Console.WriteLine("Usando tipos especficos") For Each o In a Console.WriteLine("El tipo es: {0}", o.GetType().Name) If TypeOf o Is A Then Dim tA As A = CType(o, A) tA.Mostrar() ElseIf TypeOf o Is IPrueba2 Then Dim tIPrueba2 As IPrueba2 = CType(o, IPrueba2) tIPrueba2.Mostrar() ElseIf TypeOf o Is Integer Then Dim tInt As Integer = CType(o, Integer) Console.WriteLine(tInt.ToString("00000")) ElseIf TypeOf o Is String Then Dim tStr As String = o.ToString Console.WriteLine(tStr) Else Console.WriteLine("o.ToString = {0}", o.ToString()) End If Next

Listado 6 Tal como podemos comprobar en el ltimo bucle de dicho listado, se utiliza la instruccin compuesta TypeOf ... Is para saber si un objeto es de un tipo concreto (en C# usaramos is), tambin podemos ver que usando el mtodo GetType podemos obtener el tipo subyacente as como el nombre de dicho tipo.

Si nos fijamos, al hacer la comprobacin TypeOf o Is A aqu se procesarn tanto los objetos del tipo A como los derivados de dicho tipo, lo mismo ocurre con la interfaz IPrueba2. Pero este ejemplo al ser genrico y usando la clase Object seguramente no acabar de "cuajar", por tanto vamos a crear un ejemplo en el que crearemos variables de un tipo concreto: Cliente y derivaremos un par de clases en las que agregaremos nueva funcionalidad a la clase base, posteriormente crearemos un array del tipo Cliente en el que podremos almacenar variables de cualquiera de esos tipos derivados de ella.

Nota: Por la extensin del listado, el mismo se incluye en el ZIP con el cdigo de los ejemplos (tanto para Visual Basic como para C#), en el listado 7 puedes ver cmo usar esas clases.

En dicho cdigo tendremos ocasin de ver cmo podemos implementar la interfaz IComparable para que estas clases se puedan agregar a una coleccin y posteriormente clasificarlas. Adems implementaremos la interfaz IFormattable para que, si los mostramos por la consola o usamos el mtodo Format de la clase String, podamos usar los siguientes formatos personalizados: ANS mostrar los apellidos, el nombre y el saldo NAS mostrar el nombre, los apellidos y el saldo AN mostrar los apellidos y el nombre (predeterminado) NA mostrar el nombre y los apellidos S mostrar el saldo

Sub Main() Dim acli(6) As Cliente ' acli(0) = New Cliente("Jose", "Sanchez", 125.5D) acli(1) = New ClienteOro("Luis", "Rebelde", 2500.75D) acli(2) = New ClienteMoroso("Antonio", "Perez", -500.25D) acli(3) = New Cliente("Miguel", "Rodriguez", 200) acli(4) = New ClienteMoroso("Juan", "Ruiz", -310) acli(5) = New ClienteOro("Mariano", "Alvarez", 500.33D) acli(6) = New Cliente("Carlos", "Bueno", 975) ' Console.WriteLine("Antes de clasificar:") For Each c As Cliente In acli Console.WriteLine("{0}, saldo= {1}", c, c.MostrarSaldo()) Next Array.Sort(acli)

' Console.WriteLine() Console.WriteLine("Despus de clasificar:") For Each c As Cliente In acli Console.Write("{0}, saldo= {1}", c, c.MostrarSaldo()) If TypeOf c Is ClienteOro Then Console.WriteLine(" -> $$$ es cliente ORO $$$") ElseIf TypeOf c Is ClienteMoroso Then Console.WriteLine(" -> OJO que es un cliente moroso") Else Console.WriteLine() End If Next ' Console.WriteLine() Console.WriteLine("Mostrar usando formatos:") For Each c As Cliente In acli Console.WriteLine("Usando NAS= {0:NAS}", c) Console.WriteLine("Usando AN= {0:AN}", c) Console.WriteLine("Usando S= {0:S}", c) Next ' Console.ReadLine() End Sub

Listado 7

CONSTRUCTORES Y SOBRECARGA DE CONSTRUCTORESEl punto de inicio de cualquier clase, cuando se crea una instancia en la memoria, es un mtodo especial al que se le conoce como constructor. Un constructor no devuelve ningn valor, por tanto en Visual Basic sera un mtodo de tipo Sub llamado New (en C# no se declara como void, simplemente tendr el mismo nombre de la clase). Los constructores tambin se pueden sobrecargar, es decir, pueden existir varias versiones en las que cada una de ellas reciba distintos parmetros, en nmero y/o en tipo. Debido a que todas las clases (y estructuras) deben tener un constructor, si nosotros no lo definimos de forma expresa, ser el propio compilador el que se encargue de aadirlo por nosotros, en ese caso ser un constructor en el que no se reciba ningn argumento. Aunque hay que tener presente que en el momento en que hemos definido un constructor el compilador ya no agregar ninguno de forma automtica. Esto tiene sus ventajas, ya que en ocasiones es posible que nos

interese que nuestras clases solamente se puedan instanciar si se le pasa algunos parmetros al constructor de la misma. Pero si adems de un constructor con parmetros queremos seguir manteniendo el constructor "predeterminado", entonces tendremos que declararlo aunque no escribamos nada de cdigo en el interior. En el listado 8 podemos ver la clase Cliente con tres constructores.Public Class Cliente Implements IComparable, IFormattable ' Private _nombre As String Private _apellidos As String Private _saldo As Decimal ' Public Sub New() End Sub

Public Sub New( _ ByVal elNombre As String, _ ByVal losApellidos As String) _nombre = elNombre _apellidos = losApellidos End Sub

Public Sub New( _ ByVal elNombre As String, _ ByVal losApellidos As String, _ ByVal elSaldo As Decimal) _nombre = elNombre _apellidos = losApellidos _saldo = elSaldo End Sub

Listado 8

LOS CONSTRUCTORES NO SE HEREDAN El constructor es el nico miembro de una clase que no se hereda, por tanto si necesitamos crear constructores en clases derivadas debemos declararlos de forma explcita.

LOS CONSTRUCTORES DE LAS ESTRUCTURASLos constructores de las estructuras son un caso especial, ya que siempre existir un constructor sin parmetros, el cual adems no podemos definirlo por medio de cdigo, porque es el propio compilador el que se encargar de su creacin. Por tanto en las estructuras solamente podemos definir constructores parametrizados (que reciban parmetros) y en el caso de definirlo, en el cdigo del mismo, tendremos que asignarle un valor a cualquiera de las propiedades (o campos) pblicos que tenga esa estructura, siempre y cuando no sean estticos (compartidos).

CONSTRUCTORES QUE USAN OTROS CONSTRUCTORESDebido a que los constructores pueden recibir parmetros, en algunas ocasiones nos puede ser til poder llamar a otros constructores, por ejemplo de la clase base o de la misma clase. En estos casos, en Visual Basic es fcil hacerlo, como sabemos que los constructores realmente son mtodos llamados New, los podemos usar de la misma forma que haramos con cualquier otro mtodo. Por ejemplo, si modificamos el cdigo mostrado en el listado 8, podramos hacer esto:Public Sub New( _ ByVal elNombre As String, _ ByVal losApellidos As String, _ ByVal elSaldo As Decimal)

Me.New(elNombre, losApellidos) _saldo = elSaldo

End Sub

De forma que desde el constructor que recibe tres parmetros llamemos al que recibe dos. En este caso, la instruccin o palabra clave Me representa a la instancia actual (el objeto que se ha creado en memoria). Si en lugar de llamar a otro constructor de la propia clase, queremos llamar a un constructor de la clase base, en lugar de Me, usaremos MyBase. En C# este mismo cdigo se hara de la siguiente forma:public Cliente(string elNombre, string losApellidos, decimal elSaldo) : this(elNombre, losApellidos) { _saldo = elSaldo;

}

Es decir, se llamara al otro constructor indicndolo despus del cierre de parntesis y separndolo con dos puntos. En C# la instruccin o palabra clave que hace referencia a la instancia actual es this y la que hace referencia a la clase base es: base.

CLASES ABSTRACTASTal como comentamos el mes anterior, en ocasiones tendremos la necesidad de crear clases que no se puedan usar para crear objetos, pero si para usarla como base de otras. La razn principal para que hacer que una clase no sea instanciable es que dicha clase por s sola no tenga ningn sentido, al menos para poder crear nuevos objetos de ese tipo, pero si tendr sentido si la usamos como clase base de otras clases. Por ejemplo, podramos tener una clase Animal, la cual no tendra sentido si a partir de ella se pudiesen crear nuevos objetos, ya que el concepto de animal es demasiado abstracto para poder crear un objeto a partir de l. Pero si la podramos utilizar para derivar de ella otras clases que bien podran ser a la vez abstractas o bien clases "normales". .NET Framework nos permite crear clases abstractas, las cuales son como las interfaces, pero las que pueden tener mtodos y otros miembros que tengan no solo la definicin de esos miembros sino tambin cdigo funcional. Adems, debido a que las clases abstractas estn pensadas para usarse como clases base de otras, todos los miembros son virtuales de forma predeterminada, por tanto no es necesario indicarlos usando el modificador Overridable (virtual en C#).

DECLARAR CLASES ABSTRACTASLa definicin de una clase abstracta se hace como las clases normales, salvo de que hay que usar el modificador MustInherit (abstract en C#), de esta forma le indicamos al compilador de que nuestra intencin es la de que nuestra clase sea "heredable". Como ya hemos comentado anteriormente, el concepto de clases abstractas o clases que solo se pueden usar como clases base es importante cuando queremos ofrecer cierta funcionalidad a nuestras clases, sobre todo las que formen parte de ciertas jerarquas de clases, ya que las clases abstractas nos servirn para definir el comportamiento del resto de las clases, adems de que, como las interfaces, nos permitirn disponer de cierta funcionalidad o, mejor dicho, nos permitirn dar unas pautas que los que decidan usarlas, tendrn que seguir. Pero a diferencia de las interfaces, las clases abstractas no solo representarn un contrato, sino que tambin pueden ofrecer "de fbrica" un funcionamiento que, aunque las clases derivadas no implementen, stas ya tendrn, en este aspecto funcionarn como las clases normales, ya que las clases derivadas podrn usar el cdigo implementado en ellas.

MIEMBROS ABSTRACTOSCuando comentamos que las clases abstractas son como las interfaces no solo nos referamos a que se podran usar para proporcionar polimorfismo, sino porque en las clases abstractas tambin podemos definir miembros que a su vez sean abstractos, es decir, que en las clases abstractas solamente se defina el mtodo o propiedad, pero que no tenga ninguna funcionalidad, es ms, si declaramos un miembro como abstracto la clase que se derive de la clase abstracta estar obligada a definirlo.

Esto nos ofrece la ventaja de poder definir miembros funcionales y miembros que solo tengan sentido en las clases derivadas y por tanto sern las clases derivadas las que deban definir el cdigo que los haga funcionales y le den la utilidad adecuada. Para indicar que un miembro es abstracto, debemos indicarlo usando la instruccin MustOverride (abstract en C#), de esta forma nos permitir el compilador escribir solo la definicin del mismo y no tener que escribir ningn cdigo. En las clases derivadas tendremos que usar la instruccin Overrides (override en C#) de la misma forma que lo usamos con el resto de las clases para indicar que dicho mtodo est reemplazando a un miembro definido en la clase base. Una puntualizacin: Los miembros abstractos solo se pueden definir en clases abstractas. En el cdigo incluido en el ZIP que acompaa a este artculo se incluye un ejemplo que define y usa las clases abstractas, como es habitual, se incluye cdigo para Visual Basic y C#.

CLASES SELLADAS (NO HEREDABLES)Otro concepto, que posiblemente pueda parecer que no est "ligado" con la herencia es el de las clases selladas o no heredables. Este tipo de clases no permitirn que se usen como clases base de otras nuevas clases. La existencia de las clases normales y las abstractas nos permiten derivar nuevas clases a partir de ellas, eso tiene sentido, pero, qu sentido puede tener una clase de la que no se puedan derivar nuevas clases? La razn principal para definir una clase como sellada o no heredable es precisamente porque no queremos que nadie pueda modificar el comportamiento de dicha clase, ya que al no poder usarla como base de nuevas clases, nadie podr ofrecer nueva funcionalidad, de esta forma nos aseguramos que esa clase siempre funcionar como la hemos definido. Esto es as, porque al estar "sellada" tampoco podremos definir miembros virtuales, por la sencilla razn de que nadie podr derivar nuevas clases y por tanto tampoco podr reemplazar el comportamiento de los mismos. Debido a que el comportamiento normal de una clase es que sea heredable, para poder crear clases que estn selladas, y por tanto hacerlas no heredables, debemos usar la instruccin o modificador NotInheritable (sealed en C#).

ConclusionesConfo que todo el tema tratado sobre la programacin orientada a objetos, y por extensin a la herencia, desde el punto de vista de un programador de .NET Framework nos permita afrontar todo este tema, que si bien al principio puede parecer algo "escabroso", realmente debera ser una forma natural de programar, sobre todo si tenemos en cuenta que todo el .NET Framework se basa en las clases, interfaces y dems conceptos relacionados con la POO.

Introduccin a los objetos en Visual BasicVisual Studio 2008 Otras versiones

Actualizacin: noviembre 2007 Un objeto es una estructura que contiene la informacin y los mtodos que manipulan los datos. Casi todas las tareas realizadas en Visual Basic estn asociadas con objetos. Si no tiene experiencia en programacin orientada a objetos, los siguientes trminos y conceptos le ayudarn a comenzar.

Clases y objetos

Las palabras "clase" y "objeto" se usan con tanta frecuencia en la programacin orientada a objetos que es fcil confundir los trminos. En general, una class es una representacin abstracta de algo, mientras que un objeto es un ejemplo utilizable de lo que representa la clase. La nica excepcin a esta regla la constituyen los miembros de clases compartidas, que pueden utilizarse en instancias de una clase y en variables de objeto declaradas como tipo de la clase.

Campos, propiedades, mtodos y eventos

Las clases se componen de campos, propiedades, mtodos y eventos. Los campos y propiedades representan informacin que contiene un objeto. Los campos se parecen a las variables ya que se pueden leer y establecer directamente. Por ejemplo, si tiene un objeto denominado "Car", podra almacenar su color en un campo denominado "Color". Las propiedades se recuperan y establecen como los campos, pero se implementan mediante los procedimientos propiedad Get y Set, que proporcionan ms control sobre la forma en que los valores se establecen o se devuelven. El nivel de direccionamiento indirecto entre el valor que se va a almacenar y los procedimientos que lo usan ayuda a aislar los datos y permite validar valores antes de asignarlos o recuperarlos. Los mtodos representan acciones que un objeto puede realizar. Por ejemplo, un objeto "Car" podra tener los mtodos "StartEngine", "Drive" y "Stop". Los mtodos se definen agregando procedimientos, ya sean rutinas o funciones Sub, a la clase. Los eventos son notificaciones que un objeto recibe de, o transmite a, otros objetos o aplicaciones. Los eventos permiten a los objetos realizar acciones siempre que se produce un acontecimiento especfico. Un ejemplo de evento para la clase "Car" sera un evento "Check_Engine". Puesto que Microsoft Windows es un sistema controlado por eventos, stos pueden proceder de otros objetos, aplicaciones o entradas de usuario realizadas al hacer clic con el mouse (ratn) o al presionar teclas.

Encapsulacin, herencia y polimorfismo

Los campos, propiedades, mtodos y eventos son solamente la mitad de la ecuacin de la programacin orientada a objetos. Para que la programacin orientada a objetos sea autntica los objetos deben admitir tres cualidades: encapsulacin, herencia y polimorfismo. La encapsulacin significa que un grupo de propiedades, mtodos y otros miembros relacionados se tratan como si de una sola unidad u objeto se tratase. Los objetos pueden controlar cmo se cambian propiedades o se ejecutan mtodos. Por ejemplo, un objeto puede validar valores antes de permitir cambios en la propiedad. La encapsulacin, adems, facilita la posibilidad de realizar cambios en la implementacin pasado algn tiempo, mediante una actividad denominada ocultacin de datos que permite ocultar los detalles de implementacin de los objetos. Herencia describe la posibilidad de crear nuevas clases basadas en una clase existente. La nueva clase hereda todas las propiedades, mtodos y eventos de la clase base, y puede personalizarse con propiedades y mtodos adicionales. Por ejemplo, puede crear una nueva clase denominada "Truck" basada en la clase "Car". La clase "Truck" hereda la propiedad "Color" de la clase "Car" y puede tener propiedades adicionales como "FourWheelDrive". Polimorfismo significa que puede tener mltiples clases que se pueden utilizar de forma intercambiable, si bien cada clase implementa las mismas propiedades o los mismos mtodos de maneras diferentes. El polimorfismo es importante en la programacin orientada a objetos puesto que permite usar elementos que tienen el mismo nombre, independientemente del tipo de objeto que se est utilizando en ese momento. Por ejemplo, dada una clase base "Car", el polimorfismo permite al programador definir diferentes mtodos "StartEngine" para cualquier nmero de clases derivadas. El mtodo "StartEngine" de una clase derivada denominada "DieselCar" puede ser totalmente diferente del mtodo con el mismo nombre en la clase base. Otros procedimientos o mtodos pueden usar el mtodo "StartEngine" de las clases derivadas de la misma forma, con independencia del tipo de objeto "Car" que se est utilizando en ese momento.

Sobrecarga, reemplazo y sombreado

La sobrecarga, el reemplazo y el sombreado son conceptos similares que pueden confundirse fcilmente. Aunque las tres tcnicas permiten crear miembros con el mismo nombre, existen algunas diferencias importantes.

Los miembros sobrecargados se utilizan para proporcionar diferentes versiones de una propiedad o mtodo que tienen el mismo nombre, pero que aceptan un nmero diferente de parmetros, o parmetros con diferentes tipos de datos. Las propiedades y mtodos reemplazados se utilizan para reemplazar una propiedad o mtodo heredados que no son apropiados en una clase derivada. Los miembros reemplazados deben aceptar el mismo tipo de datos y nmero de argumentos. Las clases derivadas heredan los miembros reemplazados. Los miembros sombreados se utilizan para reemplazar localmente un miembro que tiene un mbito ms amplio. Cualquier tipo puede sombrear cualquier otro tipo. Por ejemplo, puede

declarar un propiedad que sombree un mtodo heredado con el mismo nombre. Los miembros sombreados no se pueden heredar.

Clases: como planos para objetosVisual Studio 2008 Otras versiones

Actualizacin: noviembre 2007 Las clases son representaciones simblicas de objetos; describen las propiedades, campos, mtodos y eventos que forman objetos de la misma forma que los planos describen los elementos que componen un edificio. As como un plano puede utilizarse para crear varios edificios, una nica clase puede utilizarse para crear tantos objetos como sea necesario. Del mismo modo que un plano define qu partes de un edificio son accesibles a las personas que lo utilizan, las clases tambin pueden controlar el acceso de los usuarios a los elementos de objetos a travs de la encapsulacin.

Clases y objetos

Los trminos clase y objeto se utilizan a veces indistintamente, pero en realidad, las clases describen la estructura de los objetos, mientras que los objetos son instancias de clases que se pueden utilizar. Cada instancia es una copia exacta pero diferente de su clase. Puesto que un objeto es una instancia de una clase, la accin de crear un objeto se denomina creacin de instancias. Con la analoga de plano, una clase es un plano y un objeto es un edificio construido a partir de ese plano. Normalmente, al cambiar los datos en un objeto, no se cambian los datos en ningn otro objeto. (La excepcin la constituyen los miembros compartidos, miembros de clase declarados con el modificador Shared, que existen de forma independiente de las instancias especficas de una clase).

Encapsulacin

La encapsulacin es la capacidad de contener y controlar el acceso a un grupo de elementos asociados. Las clases proporcionan una de las formas ms comunes de encapsular elementos. En el ejemplo siguiente, la clase BankAccount encapsula los mtodos, campos y propiedades que describen una cuenta bancaria.

Sin la encapsulacin, debera declarar diferentes procedimientos y variables para almacenar y administrar la informacin de la cuenta bancaria, y sera difcil trabajar con ms de una cuenta bancaria a la vez. La encapsulacin permite utilizar datos y procedimientos de la clase BankAccount como una unidad. Puede trabajar con varias cuentas bancarias al mismo tiempo sin confusin, puesto que cada cuenta se representa mediante una instancia nica de la clase. La encapsulacin tambin permite controlar la forma de utilizar los datos y los procedimientos. Se pueden utilizar modificadores de acceso, como Private o Protected, para evitar que unos procedimientos externos ejecuten mtodos de clase o lean y modifiquen datos en propiedades y campos. Debe declarar detalles internos de una clase como Private para evitar que se utilicen fuera de su clase; esta tcnica se llama ocultacin de datos y es el modo de proteger informacin del cliente, como un saldo de cuenta por ejemplo. Una regla bsica de la encapsulacin es que los datos de clase slo se deben modificar o recuperar mediante mtodos o procedimientos Property. Al ocultar los detalles de implementacin de las clases se evita que sean utilizados de forma no deseada y hace posible la modificacin posterior de tales elementos sin problemas de compatibilidad. Por ejemplo, en las versiones posteriores de la clase BankAccount se podra cambiar el tipo de datos del campo AccountBalance sin peligro de interrumpir otras aplicaciones que se basan en que ese campo tenga un tipo de datos especfico.

Herencia

Al igual que para las estructuras de Visual Basic, puede utilizar las clases para definir tipos de datos que encapsulan un grupo de elementos relacionados. No obstante, a diferencia de las estructuras, las clases de Visual Basic pueden heredar y extender las caractersticas de otras clases. Las clases que sirven de base para nuevas clases se denominan clases base. Las clases que se derivan de clases base se denominan clases derivadas. Las clases derivadas heredan todos los campos, propiedades, mtodos y eventos de la clase base. Esto significa que puede desarrollar y depurar una clase una vez y reutilizarla despus como base de otras clases. En el siguiente ejemplo se define una clase base que representa una cuenta bancaria genrica y una clase especfica que hereda las propiedades de la clase base pero que se personaliza para describir una cuenta corriente.

VB C# C++ F#

JScript

Copiar Class BankAccount Private AccountNumber As String Private AccountBalance As Decimal Private HoldOnAccount As Boolean = False Public Sub PostInterest() ' Add code to calculate the interest for this account. End Sub ReadOnly Property Balance() As Decimal Get ' Return the available balance. Return AccountBalance End Get End Property End Class

Class CheckingAccount Inherits BankAccount Sub ProcessCheck() ' Add code to process a check drawn on this account. End Sub End Class

Para obtener ms informacin sobre herencias, consulte Fundamentos de la herencia.

Miembros compartidos

De forma predeterminada, los datos de clase se especifican para cada instancia de la clase, pero en ocasiones puede ser deseable compartir un solo elemento de datos entre todos los objetos creados a partir de una clase. En casos como ste, utilice el modificador Shared para hacer que una variable comparta el mismo valor en todas las instancias de una clase (los miembros Shared a veces se llaman "miembros estticos" en otros lenguajes de programacin). Los mtodos compartidos pueden llamarse directamente mediante un nombre de clase sin necesidad de crear previamente una instancia de la clase. Para obtener ms informacin acerca de miembros compartidos, consulte Miembros compartidos en Visual Basic.

Sombrear

Las clases derivadas pueden utilizar la palabra clave Shadows para declarar un miembro con el mismo nombre que un miembro heredado. El tipo de datos de los miembros sombreados no es necesario que sea el mismo que el del miembro que se sombrea. Por ejemplo, una propiedad puede sombrear una variable de tipo Integer. Para obtener ms informacin acerca de miembros compartidos, consulte Sombrear en Visual Basic.

Tutorial: Definir clases (Visual Basic)Visual Studio 2010 Otras versiones

Este tutorial muestra cmo definir clases que se pueden utilizar luego para crear objetos.Tambin muestra cmo agregar propiedades y mtodos a las clases nuevas, e indica cmo inicializar un objeto.

NotaEs posible que su equipo muestre nombres o ubicaciones diferentes para algunos de los elementos de la interfaz de usuario de Visual Studio incluidos en las instrucciones siguientes. La edicin de Visual Studio que se tenga y la configuracin que se utilice determinan estos elementos. Para obtener ms informacin, vea Valores de configuracin de Visual Studio.

Para definir una clase1. 2. 3. 4. 5. Cree un proyecto haciendo clic en Nuevo proyecto en el men Archivo.Aparecer el cuadro de dilogo Nuevo proyecto. Seleccione Aplicacin para Windows de la lista de plantillas del proyecto de Visual Basic para mostrar el nuevo proyecto. Agregue una clase nueva al proyecto haciendo clic en Agregar clase en el men Proyecto.Aparecer el cuadro de dilogo Agregar nuevo elemento. Seleccione la plantilla Clase. Asigne a la nueva clase el nombre UserNameInfo.vb y, a continuacin, haga clic en Agregar para mostrar el cdigo de la nueva clase.

VB C# C++ F# JScript

Copiar

Public Class UserNameInfo End Class

NotaPuede utilizar el Editor de cdigo de Visual Basic para agregar una clase al formulario de inicio escribiendo la palabra clave Class seguida del nombre de la clase nueva.El Editor de cdigo proporciona la instruccin End Class correspondiente.

6.

Defina un campo privado para la clase; para ello, agregue el siguiente cdigo entre las instrucciones Class y End Class:

VB C# C++ F# JScript

Copiar

Private userNameValue As String

Declarar el campo como Private quiere decir que slo se puede utilizar dentro de la clase.Se pueden utilizar modificadores de acceso ms amplio, por ejemplo Public, para hacer que los campos estn disponibles desde fuera de la clase.Para obtener ms informacin, vea Niveles de acceso en Visual Basic. 7. Defina una propiedad para la clase agregando el cdigo siguiente:

VB C# C++ F# JScript

Copiar

Public Property UserName() As String Get ' Gets the property value. Return userNameValue End Get

Set(ByVal Value As String) ' Sets the property value. userNameValue = Value End Set End Property

8.

Defina un mtodo para la clase agregando el cdigo siguiente:

VB C# C++ F# JScript

Copiar

Public Sub Capitalize() ' Capitalize the value of the property. userNameValue = UCase(userNameValue) End Sub

9.

Defina un constructor parametrizado para la clase nueva agregando un procedimiento denominado Sub New:

VB C# C++ F# JScript

Copiar

Public Sub New(ByVal UserName As String) ' Set the property value. Me.UserName = UserName End Sub

Cuando se crea un objeto basado en esta clase, se llama al constructor Sub New automticamente.Este constructor establece el valor del campo que contiene el nombre de usuario.

Para crear un botn que pruebe la clase1. Cambie el formulario de inicio al modo de diseo haciendo clic con el botn secundario del mouse en su nombre desde el Explorador de soluciones y, a continuacin, haga clic en Diseador de vistas.De forma predeterminada, el nombre que se asigna al formulario de inicio para los proyectos de aplicacin para Windows es Form1.vb.Aparecer el formulario principal. Agregue un botn al formulario principal y haga doble clic en l para mostrar el cdigo del controlador de eventos Button1_Click.Agregue el cdigo siguiente para llamar al procedimiento de prueba:

2.

VB C# C++ F# JScript

Copiar

' Create an instance of the class. Dim user As New UserNameInfo("Moore, Bobby") ' Capitalize the value of the property. user.Capitalize() ' Display the value of the property. MsgBox("The original UserName is: " & user.UserName)

' Change the value of the property. user.UserName = "Worden, Joe" ' Redisplay the value of the property. MsgBox("The new UserName is: " & user.UserName)

Para ejecutar la aplicacin1. Presione F5para ejecutar la aplicacin.Llame al procedimiento de prueba haciendo clic en el botn del formulario.Muestra un mensaje que indica que el UserName original es "MOORE, BOBBY", porque el procedimiento llam al mtodo Capitalize del objeto. Haga clic en Aceptar para descartar el cuadro de mensaje.El procedimiento Button1 Click cambia el valor de la propiedad UserName y muestra un mensaje que indica que el nuevo valor de UserName es "Worden, Joe."

2.

Clases y mdulosVisual Studio 2008 Otras versiones

Actualizacin: noviembre 2007 Tanto las clases como los mdulos son tipos de referencia que encapsulan los elementos definidos en ellos, pero difieren en la forma en que se realiza el acceso a los elementos desde otros procedimientos.

Diferencias entre clases y mdulos

La diferencia principal entre clases y mdulos consiste en que pueden crearse instancias de clases como objetos pero no de mdulos. Como slo existe una copia de los datos de un mdulo estndar, cuando una parte del programa cambia una variable pblica en un mdulo estndar, cualquier otra parte del programa obtendr el mismo valor si lee luego esa variable. En comparacin, los datos de objeto existen individualmente para cada objeto con instancias. Otra distincin es que, a diferencia de los mdulos estndar, las clases pueden implementar interfaces.

Nota:Cuando el modificador Shared se aplica a un miembro de clase, est asociado con la propia clase en lugar de con una instancia determinada de la clase. Se tiene acceso directo al miembro mediante el nombre de clase, de la misma manera que se tiene acceso a los miembros de mdulos. Para obtener ms informacin acerca de miembros compartidos, consulte Miembros compartidos en Visual Basic.

Las clases y los mdulos tambin emplean mbitos diferentes para sus miembros. Los miembros definidos dentro de una clase tienen el mbito de una instancia especfica de la clase y slo existen mientras dure el objeto. Para tener acceso a los miembros de clases desde el exterior de una clase, debe utilizar los nombres completos con el formato Objeto.Miembro. Por otro lado, los miembros declarados dentro de un mdulo son de manera predeterminada accesibles pblicamente y se puede obtener acceso a ellos mediante cualquier cdigo que tenga acceso al mdulo. Esto significa que las variables en un mdulo estndar son de hecho variables globales porque son visibles desde cualquier parte del proyecto y existen durante toda la vida til del programa.

Duracin de los objetos: cmo se crean y destruyen (Visual Basic)Visual Studio 2010 Otras versiones

Una instancia de una clase (un objeto) se crea mediante la palabra clave New.A menudo hay que realizar tareas de inicializacin en los objetos nuevos antes de utilizarlos.Entre las tareas de inicializacin comunes se incluyen abrir archivos, conectar con bases de datos y leer valores de claves del Registro.Visual Basic controla la inicializacin de objetos nuevos mediante unos procedimientos denominados constructores (mtodos especiales que proporcionan control sobre la inicializacin). Common Language Runtime (CLR) libera un objeto cuando ste ha salido del mbito.Visual Basic controla la liberacin de recursos del sistema mediante unos procedimientos denominados destructores.Juntos, los constructores y destructores permiten la creacin de bibliotecas de clases robustas y predecibles.

Utilizar constructores y destructores

Los constructores y destructores controlan la creacin y destruccin de objetos.Los procedimientos Sub New y Sub Finalize de Visual Basic inicializan y destruyen objetos; reemplazan a los mtodos Class_Initialize y Class_Terminate que se utilizaban en Visual Basic 6.0 y versiones anteriores.

Sub NewEl constructor Sub New slo puede ejecutarse una vez cuando se crea una clase.Slo se le puede llamar explcitamente desde la primera lnea de cdigo de otro constructor en la misma clase o en una clase derivada.Adems, el cdigo del mtodo Sub New siempre se ejecuta antes de cualquier otro cdigo en una clase.Visual Basic 2005 y las versiones posteriores crean implcitamente en tiempo de ejecucin un constructor Sub New si no define explcitamente un procedimiento Sub New para una clase. Para crear un constructor para una clase, cree un procedimiento denominado Sub New en cualquier parte de la definicin de clase.Para crear un constructor parametrizado, especifique los nombres y los tipos de datos de los argumentos de Sub New tal como lo hara en cualquier otro procedimiento, como en el cdigo siguiente:

VB C# C++ F# JScript

Copiar

Sub New(ByVal s As String)

Con frecuencia, los constructores estn sobrecargados, como en el cdigo siguiente:

VB C# C++ F# JScript

Copiar

Sub New(ByVal s As String, i As Integer)

Cuando se define una clase derivada de otra, la primera lnea del constructor debe ser una llamada al constructor de la clase base, a no ser que sta tenga un constructor accesible que no requiera parmetros.Por ejemplo, para llamar a la clase base que contiene el constructor anterior, sera MyBase.New(s).En caso contrario, MyBase.New es opcional y el tiempo de ejecucin de Visual Basic la llama implcitamente. Despus de escribir cdigo para llamar al constructor del objeto primario, se puede agregar cdigo de inicializacin al procedimiento Sub New.Sub New puede aceptar argumentos cuando se llama como constructor parametrizado.Estos parmetros se pasan desde el procedimiento que llama al constructor; por ejemplo, Dim AnObject As New ThisClass(X).

Sub FinalizeAntes de liberar objetos, CLR llama automticamente al mtodo Finalize para los objetos que definen un procedimiento Sub Finalize.El mtodo Finalize puede contener cdigo que es necesario ejecutar inmediatamente antes de destruir un objeto, por ejemplo el cdigo para cerrar archivos y guardar

informacin de estado.Puesto que se produce una ligera disminucin del rendimiento al ejecutar Sub Finalize, este mtodo slo debe definirse cuando sea necesario liberar objetos explcitamente.

NotaEl recolector de elementos no utilizados de CLR no se deshace de los objetos no administrados (ni puede eliminarlos), que son aquellos que el sistema operativo ejecuta directamente, fuera del entorno de CLR.Esto se debe a que hay que deshacerse de los objetos no administrados diferentes de maneras distintas.Esa informacin no est asociada directamente al objeto no administrado; se debe buscar en la documentacin del objeto.Una clase que utiliza objetos no administrados debe deshacerse de ellos en su mtodo Finalize.

El destructor Finalize es un mtodo protegido al que slo se puede llamar desde la clase a la que pertenece o desde clases derivadas.El sistema llama automticamente a Finalize cuando se destruye un objeto, por lo que no se debe llamar explcitamente a Finalize desde fuera de una implementacin de su clase derivada. A diferencia de Class_Terminate, que se ejecuta en cuanto un objeto se establece en nothing, normalmente se suele producir un retraso desde que un objeto pierde el mbito hasta que Visual Basic llama al destructor Finalize.Visual Basic 2005 y versiones posteriores permiten un segundo tipo de destructor, Dispose, al que se puede llamar explcitamente en cualquier momento para liberar recursos inmediatamente.

NotaUn destructor Finalize no debera producir excepciones porque la aplicacin no puede controlarlas y pueden hacer que la aplicacin finalice.

Cmo funcionan los mtodos New y Finalize en una jerarqua de clasesSiempre que se crea una instancia de una clase, Common Language Runtime (CLR) intenta ejecutar un procedimiento denominado New, si existe en ese objeto.New es un tipo de procedimiento denominado constructor que se usa para inicializar los objetos nuevos antes de que se ejecute cualquier otro cdigo en un objeto.Un constructor New puede utilizarse para abrir archivos, conectarse a bases de datos, inicializar variables y realizar cualquier otra tarea necesaria antes de poder utilizar un objeto. Cuando se crea una instancia de una clase derivada, se ejecuta primero el constructor Sub New de la clase base, seguido de los constructores de las clases derivadas.Esto se debe a que la primera lnea de cdigo en un constructor Sub New utiliza la sintaxis MyBase.New() para llamar al constructor de la clase situada inmediatamente por encima en la jerarqua de clases.Despus se llama al constructor Sub New para cada clase de la jerarqua hasta llegar al constructor de la clase base.En este punto, se ejecuta el cdigo del constructor para la clase base, seguido del cdigo en cada constructor de todas las clases derivadas, ejecutndose en ltimo lugar el cdigo de las clases ms derivadas.

Cuando un objeto deja de ser necesario, CLR llama al mtodo Finalize para ese objeto antes de liberar su memoria.El mtodo Finalize se denomina destructor porque realiza tareas de limpieza, como guardar informacin de estado, cerrar archivos y conexiones a bases de datos, y otras tareas que deben realizarse antes de liberar el objeto.

Interfaz IDisposable

A menudo, las instancias de clase controlan los recursos que no administra CLR, como identificadores de Windows y conexiones de bases de datos.Estos recursos se deben desechar en el mtodo Finalize de la clase, a fin de liberarlos cuando el recolector de elementos no utilizados destruya el objeto.Sin embargo, el recolector de elementos no utilizados slo destruye los objetos cuando CLR requiere ms memoria libre.Esto significa que los recursos pueden no liberarse hasta mucho despus de que el objeto salga del mbito. Para complementar la recoleccin de elementos no utilizados, las clases pueden proporcionar un mecanismo para administrar los recursos del sistema activamente si implementan la interfaz IDisposable.IDisposable tiene un mtodo, Dispose, al que deberan llamar los clientes cuando terminan de usar un objeto.Se puede utilizar el mtodo Dispose para liberar recursos inmediatamente y realizar tareas como cerrar archivos y conexiones de bases de datos.A diferencia del destructor Finalize, el mtodo Dispose no se llama automticamente.Los clientes de una clase deben llamar explcitamente a Dispose cuando se desea liberar recursos inmediatamente.

Implementar IDisposableUna clase que implementa la interfaz IDisposable debera incluir estas secciones de cdigo:

Un campo para mantener el seguimiento de si se ha desechado el objeto:

Copiar Protected disposed As Boolean = False Una sobrecarga de Dispose que libera los recursos de la clase.Los mtodos Dispose y Finalize de la clase base deben llamar a este mtodo:

Copiar Protected Overridable Sub Dispose(ByVal disposing As Boolean) If Not Me.disposed Then If disposing Then ' Insert code to free managed resources. End If ' Insert code to free unmanaged resources. End If Me.disposed = True End Sub Una implementacin de Dispose que contiene slo el cdigo siguiente:

Copiar Public Sub Dispose() Implements IDisposable.Dispose Dispose(True) GC.SuppressFinalize(Me) End Sub Un reemplazo del mtodo Finalize que contiene slo el cdigo siguiente:

Copiar Protected Overrides Sub Finalize() Dispose(False) MyBase.Finalize() End Sub

Derivar de una clase que implementa IDisposableUna clase derivada de una clase base que implementa la interfaz IDisposable no necesita reemplazar ninguno de los mtodos base a menos que utilice recursos adicionales que se deban desechar.En esa situacin, la clase derivada debera reemplazar el mtodo Dispose(disposing) de la clase base para desechar los recursos de la clase derivada.Este reemplazo debe llamar al mtodo Dispose(disposing) de la clase base.

Copiar Protected Overrides Sub Dispose(ByVal disposing As Boolean) If Not Me.disposed Then If disposing Then ' Insert code to free managed resources. End If ' Insert code to free unmanaged resources. End If MyBase.Dispose(disposing) End Sub

Una clase derivada no debera reemplazar los mtodos Dispose y Finalize de la clase base.Cuando se llama a estos mtodos desde una instancia de una clase derivada, la implementacin de estos mtodos en la clase base llama al reemplazo del mtodo Dispose(disposing) en la clase derivada.

Recoleccin de elementos no utilizados y el destructor Finalize

.NET Framework utiliza el sistema de recoleccin de elementos no utilizados por traza de referencias para liberar peridicamente los recursos no utilizados.Visual Basic 6.0 y las versiones anteriores utilizaban un sistema diferente denominado recuento de referencias para administrar los recursos.Aunque ambos sistemas realizan la misma funcin automticamente, existen algunas diferencias importantes. CLR destruye peridicamente objetos cuando el sistema determina que ya no son necesarios.Los objetos se liberan con mayor rapidez cuando los recursos del sistema son escasos y con menor frecuencia en caso contrario.El retraso que se produce entre el momento en que un objeto pierde su mbito y el momento en que CLR lo libera significa que, a diferencia de lo que ocurre con los objetos en Visual Basic 6.0 y versiones anteriores, no se puede determinar exactamente cundo se destruir el objeto.En tal situacin, se dice que los objetos tienen duracin no determinista.En la mayora de los casos, la duracin no determinista no cambia la forma de escribir las aplicaciones, siempre que se recuerde que el destructor Finalize puede no ejecutarse inmediatamente cuando un objeto pierde su mbito. Otra diferencia entre los sistemas de recoleccin de elementos no utilizados tiene que ver con el uso de Nothing.Para aprovechar el recuento de referencias de Visual Basic 6.0 y versiones anteriores, los programadores a veces asignaban Nothing a variables de objeto para liberar las referencias que esas variables almacenaban.Si la variable almacenaba la ltima referencia al objeto, los recursos del objeto se liberaban inmediatamente.En las versiones posteriores de Visual Basic, aunque puede haber casos en los que este procedimiento sea an til, su realizacin nunca ocasionar que el objeto de referencia libere sus recursos inmediatamente.Para liberar inmediatamente los recursos, utilice el mtodo Dispose del objeto, si est disponible.La nica vez en que debe establecerse una variable en Nothing es cuando su duracin sea larga con relacin al tiempo que necesita el recolector de elementos no utilizados para detectar objetos hurfanos.

Cmo: Implementar el modelo DisposeFinalize (Visual Basic)Visual Studio 2008 Otras versiones

Actualizacin: noviembre 2007

El modelo DisposeFinalize garantiza que se liberan los recursos cuando ya no se necesita el objeto.

Ejemplo

La clase ResourceClass del ejemplo siguiente utiliza recursos administrados y no administrados y, a continuacin, utiliza el modelo DisposeFinalize para desecharlos correctamente. Los recursos y sus funciones son:

La implementacin del mtodo Dispose, que permite a los usuarios de la clase desechar las instancias de clase. Este mtodo llama a Dispose(True) para desechar los recursos del objeto y, a continuacin, llama a SuppressFinalize para evitar que el cdigo de finalizacin se ejecute una segunda vez. El reemplazo del mtodo base Finalize, que permite al recolector de elementos no utilizados de Common Language Runtime (CLR) desechar las instancias de clase. Este mtodo llama a Dispose(False) para desechar los recursos del objeto. Observe que si se llama a Dispose previamente para el objeto, su llamada a SuppressFinalize evitara que el recolector de elementos no utilizados llamase al mtodo Finalize. La sobrecarga del mtodo Dispose, que lleva a cabo el trabajo de eliminacin. Toma un parmetro de tipo Boolean, disposing, que indica si el cdigo ha iniciado la eliminacin del objeto. Cuando desecha un objeto, tambin se deben desechar todos sus recursos. Cuando el reco