Clases. Introducción. Marco Besteiro y Miguel Rodríguez

Marco Besteiro y Miguel Rodríguez Clases Clases. Introducción La Programación Orientada a Objetos permite realizar grandes programas mediante la unión de elementos más simples, que pueden ser diseñados y comprobados de manera independiente del programa que va a usarlos. Muchos de estos elementos podrán ser reutilizados en otros programas. A estas “piezas”, “módulos” o "componentes", que interactúan entre sí cuando se ejecuta un programa, se les denomina objetos. Los objetos contienen datos y funciones que actúan sobre esos datos. Durante la ejecución de un programa, los objetos interactúan entre sí pasándose mensajes y devolviendo respuestas a estos mensajes. Es fundamental darse cuenta de que un objeto no necesita conocer el funcionamiento interno de los demás objetos para poder interactuar con ellos (igual que el hombre no necesita conocer cómo funciona el motor de su coche, el televisor o un ordenador para poder utilizarlos), sino que le es suficiente con saber la forma en que debe enviarle sus mensajes y cómo va a recibir la respuesta (al hombre le puede ser suficiente para utilizar el coche saber cómo conducir – acelerar, utilizar el volante, etc...-, cómo funcionan el interruptor, el dial del volumen y los botones de cambio de canal para utilizar un televisor, etc). Sucede a menudo que hay que utilizar varios ejemplares análogos de un determinado tipo (por ejemplo varias ventanas en la pantalla del PC, varios usuarios, varios clientes, varias cuentas corrientes de un banco, etc.). La definición genérica de estos objetos análogos se realiza mediante la clase. Así, una clase contiene una completa y detallada descripción de la información y de las funciones que contendrá cada objeto de esa clase. Los objetos son las variables concretas que se crean de una determinada clase. A veces se llaman también instancias. Así, se habla de crear un objeto o instancia de una clase. Las clases son verdaderos tipos de datos definidos por el usuario o por el sistema y pueden ser utilizados de igual manera que los tipos de datos simples, tales como int, float, etc. Un objeto tiene su propio conjunto de datos o variables miembro, aunque no de funciones, ya que las que se aplican a un objeto concreto son propias de la clase a la que pertenece el objeto. Para proteger a las variables de modificaciones no deseadas se introduce el concepto de encapsulación, ocultamiento o abstracción de datos. De ordinario una clase ofrece un conjunto de métodos públicos a través de los cuales se puede actuar sobre los datos, que serán privados. Estas funciones o métodos públicos constituyen la interfaz de la clase, es decir, el elemento que el programador puede utilizar para comunicarse con los objetos. . De esta forma se garantiza que se hace buen uso de los objetos, manteniendo la coherencia de la información. Esto sería imposible si se accediera libre e independientemente a cada variable miembro. Al usuario le es suficiente con saber 1/35 Marco Besteiro y Miguel Rodríguez Clases cómo comunicarse con un objeto, pero no tiene por qué conocer el funcionamiento interno del mismo. Se desea recalcar aquí que el concepto de interfaz es muy diferente al de interface, que se estudiará más adelante Concepto de clase. Forma general Una clase sencilla Cuando se escribe un programa en un lenguaje orientado a objetos, se definen previamente las clases que van a describir las características y comportamiento de los objetos que se van a utilizar. Esto sucede de igual manera en C#. Una clase está compuesta por un conjunto de datos –llamados campos o variables miembro- y unos métodos que son funciones que operan sobre esos datos. El conjunto de campos y métodos de una clase constituyen sus miembros. El siguiente es un ejemplo de definición y declaración de una clase: public class Rectangulo { //variables miembro, datos o atributos int x; int y; private double ancho; private double largo; //funciones miembro o métodos public Rectángulo (double w, double h) { x = 0; y = 0; ancho = w; largo = h; } public double CalcularArea() { return ancho*largo; } } Objetos Un objeto o instancia es un ejemplar concreto de una clase. En realidad, los objetos son variables de tipo clase. Es importante comprender muy bien la diferencia entre clase y objeto. Clase es la propia definición de un tipo de dato, realizada por el programador o proporcionada por el sistema. Es una abstracción lógica. Sin embargo, el objeto es un ejemplar de una clase, que tiene una existencia física ya que está físicamente en memoria, de la misma forma que una variable de un tipo valor es un ejemplar del tipo de la variable. Por ejemplo: 2/35 Marco Besteiro y Miguel Rodríguez Clases int unaVariable = 7; En esta sentencia, el programador distingue perfectamente entre el tipo de dato –que es un entero, concepto o abstracción lógica- y la variable de ese tipo, que es un “ejemplar” de un entero, con una realidad física, almacenado en memoria y con un valor de 7. De igual forma, hay que distinguir entre clase –tipo de dato- y objeto –ejemplar de ese tipo de dato, de esa clase-. Para crear un objeto o instancia de una clase hay que dar dos pasos: a ) Crear una variable de tipo referencia que almacene la referencia al objeto. Por ejemplo, Rectángulo unRect; En la sentencia anterior se reserva espacio en la pila o stack para la variable unRect que es una referencia a un objeto de la clase Rectángulo. Después de este paso, unRect no apunta a nada, no referencia ningún objeto. b ) Crear un objeto de la clase y asignarlo a la referencia anterior. unRect = new Rectángulo(5,7); En la sentencia anterior, el operador new seguido de un constructor de la clase crea un objeto de la clase Rectángulo –es decir, reserva el espacio de memoria que sea necesario para un objeto de esa clase- y devuelve una referencia al objeto creado. El símbolo = asigna el objeto recién creado a la referencia unRect. El objeto se almacena en el heap o montón y la referencia en el stack o pila. Lo que se almacena en la variable no es el objeto en sí sino una referencia al objeto que ha sido creado previa asignación del bloque de memoria necesario. Es importante que el lector comprenda que esa variable unRect no es el objeto creado sino una referencia al mismo. El objeto se almacena en el montón. Montón Pila unRect Referencias a objetos de la clase Rectángulo doRect 3/35 x 0 y 0 ancho 5.0 largo 7.0 x 0 y 0 ancho 23.0 largo 347.0 Objetos Marco Besteiro y Miguel Rodríguez Clases Figura 5.1 En la figura 5.1 puede verse dos referencias unRect y doRect a objetos de la clase Rectángulo. Habitualmente, estos dos pasos se reducen a uno sólo: Rectángulo unRect = new Rectángulo(5,7); En la expresión anterior se crea una referencia unRect de tipo Rectángulo y se le asigna un objeto creado con el operador new. new crea el objeto físico, que es almacenado en memoria, el objeto, y unRect es una referencia a un objeto de tipo Rectángulo. El operador = asigna el objeto a la referencia. Aunque el objeto y la referencia son distintos, sin embargo es muy habitual hablar del objeto unRect en lugar de decir el objeto de la clase Rectangulo que está referenciado por unRect. Esta manera de hablar no produce ningún tipo de confusión y se utiliza con frecuencia. Forma general de una clase Una clase es una estructura de datos que puede contener miembros dato (constantes, y campos, como x, y, ancho y largo), funciones miembro (métodos, propiedades, indexadores, eventos, operadores, constructores y destructores como CacularArea() y Rectángulo()) y tipos anidados. Las clases se declaran utilizando la palabra clave class. La estructura general de una clase es la siguiente: [atributos] [modificadores] class identificador [:lista-clases-base] { //cuerpo de la clase //Declaraciones de los miembros de la clase } Una declaración de clase consiste en un conjunto opcional de atributos –se estudiarán más adelante- seguidos por un conjunto también opcional de modificadores de clase, por la palabra reservada class y un identificador que da nombre a la clase. Realmente, la sintaxis es muy parecida a Java o C++. Después puede indicarse la clase base de la que deriva o/y las interfaces que implementa, separadas por comas. Por ejemplo class MiPrimeraClase { //Cuerpo de la clase } En C# sólo se permite herencia simple, es decir, sólo puede heredarse desde una clase. Sin embargo, como en Java, se puede implementar más de una interface. 4/35 Marco Besteiro y Miguel Rodríguez Clases Los posibles modificadores que puede tener una clase son new, public, protected, internal, private, abstract y sealed. Los modificadores public, protected, internal y private son modificadores de control de acceso a la clase. Estos modificadores determinan la visibilidad de los miembros de una clase. Se realizará una explicación detallada de los modificadores, más adelante, en este mismo capítulo. Aunque se volverá a recalcar al hablar de los tipos de acceso, en este libro se seguirán la recomendaciones de Microsoft respecto a cómo escribir los nombres de los miembros de una clase. • Se escriben con minúsculas los nombres de parámetros y campos privados o protegidos de una clase. Por ejemplo: private int unEntero; protected string cadena; • Los miembros públicos, las clases, etc, se escriben con mayúsculas. Por ejemplo: class MiClase{} namespace MiNamespace; • Las constantes con mayúsculas. Por ejemplo: public const double PI = 3.14; • Los nombre de una sóla letra con minúsculas: int x=8; private string s; Los miembros de una clase pueden ser: • • • • • • • • Constructores Destructores Constantes Campos Métodos Propiedades Indexadores Operadores A continuación, se estudian cada uno de ellos. Constantes y miembros de sólo lectura. Las constantes representan valores constantes asociados con la clase. El modificador const indica que un determinado campo es una constante y, por lo tanto, no puede ser modificada a lo largo del programa. 5/35 Marco Besteiro y Miguel Rodríguez Clases Por ejemplo: class Matemáticas { public const double PI=3.141592; } Una constante es un valor que no puede ser cambiado y no se le puede asignar ningún valor. Por eso es imprescindible inicializarla en la propia clase. Esto significa que no podría haberse incluido en la clase anterior una línea como la siguiente: public const double E; Un campo de sólo lectura –readonly- es muy parecido a una constante pero proporciona un poco más de flexibilidad que una constante, ya que permite inicializarlo después –por ejemplo- de algún cálculo. En el siguiente ejemplo, se asigna un valor a un campo de este tipo en el constructor de la clase: class Personal { public readonly string password; public Personal(string unaPalabra) { password=unaPalabra; } } Campos. Los campos de una clase almacenan información del objeto de la clase que se ha creado. Son aquéllas características que diferencian dos objetos de una misma clase y determinan su apariencia o estado. El acceso a los campos o miembros dato puede ser directo o bien a través de métodos o propiedades, dependiendo de la visibilidad de los campos –es decir, de los modificadores de cada variable. Los campos de un objeto se invocan con el operador punto (.). C# permite definir como campos tanto tipos valor como tipos referencia. En el primer caso, los objetos que se creen almacenarán una copia de las variables de tipo valor y en el segundo, una referencia a los objetos. También permite definir otra clase de miembros como propiedades, delegates, etc... Los campos de una clase se denominan a veces, campos o variables de instancia o de objeto en contraposición a las variables estáticas o de clase. Se llaman así porque cada instancia u objeto contiene su propia copia de cada campo o variable. Los datos de un objeto son propios y están separados –incluso físicamente- de los datos de otro objeto. Por esta razón, los cambios que se realicen en los campos de un objeto no afectan para nada a los campos de los demás objetos, aunque sean del mismo tipo de clase. Esto no sucede así con los campos de clase, porque todos los objetos comparten la misma variable físicamente. Por ejemplo: using System; 6/35 Marco Besteiro y Miguel Rodríguez Clases public class Rectangulo { //variables miembro, datos o atributos int x; int y; private double ancho; private double largo; //funciones miembro o métodos public Rectángulo (double w, double h) { x = 0; y = 0; ancho = w; largo = h; } public Set_Rectángulo(int x0,int y0,int w,int h) { x = x0; y = y0; ancho = w; largo = h; } public double CalcularArea() { return ancho*largo; } public void Imprimir() { Console.WriteLine(“Coordenadas: x={0}, y={1}”,x,y}; Console.WriteLine(“Ancho={0}, Largo={1}”,ancho,largo}; } } public static void Main() { Rectangulo unRect=new Rectangulo(55,44); unRect.Set_Rectangulo(10,15,100,58); unRect.Imprimir(); int area=unRect.CalcularArea(); Console.WriteLine(“Area={0}”,area); } La salida de este programa es: Coordenadas: x = 10, y = 15 Ancho=100, Largo=58 Area=5800 Las variables de instancia se declaran en la clase pero sus valores se inicializan y cambian en los objetos. Además de las variables de instancia hay variables de clase. Se explicarán con detalle más adelante, en este mismo capítulo. 7/35 Marco Besteiro y Miguel Rodríguez Clases Métodos. Forma general Los métodos de una clase son porciones o bloques de código a los que los objetos de esa clase pueden llamar para que sean ejecutados. Generalmente operan sobre los campos. Las clases no tiene limitación en cuanto al número de métodos. Los métodos pueden tener parámetros y devolverlos. Si un método no devuelve nada, se utiliza la palabra void. La estructura general de un método es: [modificadores] tipo_de_retorno nombreDelMetodo (Parámetros_opcionales) { //cuerpo del método } Los métodos de un determinado objeto se invocan con el operador punto (.). Todo método tiene que tener un nombre (nombreDelMetodo); ninguno, uno o varios parámetros con modificadores también opcionales; puede devolver cualquier tipo de dato u objeto (tipo_de_retorno), incluso los definidos por el programador; y unos modificadores opcionales. Aunque puede haber más, ahora se va a explicar únicamente los que definen método estáticos –static-. Miembros estáticos Hay ocasiones en los que un miembro de una clase, ya sea campo o método, hace más referencia a la clase –es decir, a todos los objetos de la clase- que a cada objeto en concreto. Suponga –por ejemplo- que se desea llevar una cuenta del número de objetos de una determinada clase en un programa. C# proporciona un camino para crear un miembro que pueda utilizarse por sí mismo sin referirse a una instancia u objeto específico. Para ello, en su definición, el miembro ha de ir precedido por el modificador static. Cuando se declara un miembro como estático, se puede acceder a él sin haber creado ningún objeto en particular. Esto es lo que sucede con el método Main() que debe ser declarado como static porque tiene que ser invocado al inicio del programa, es decir, cuando todavía no se ha creado ningún objeto de ninguna clase. Al tener este modificador, el método Main() puede ser invocado sin necesidad de crear previamente ningún objeto. Los campos declarados como static son variables globales. Cuando se crean objetos de una clase que tiene un campo static, no se hace ninguna copia de él. Todos los objetos de esa clase comparten una única copia del mismo campo. Si uno de ellos lo modifica, quedará modificado para todos ellos. por esta razón, este tipo de miembros se denominan campos o métodos estáticos o de clase o , en contraposición a los métodos o campos de objeto o de instancia. 8/35 Marco Besteiro y Miguel Rodríguez Clases Fuera de la clase en la que han sido definidos, los métodos y campos estáticos se pueden utilizar independientemente de cualquier objeto. Únicamente es necesario especificar el nombre de la clase seguido del operador punto y del nombre del miembro, de la forma: NombreDeLaClase.metodoStatic( ); NombreDeLaClase.campoStatic; A continuación se propone un ejemplo que puede servir para aclarar este concepto: Se trata de diseñar una clase Alumno en la cual se incluya la nota media para ingresar en la universidad y que tenga en cuenta la “nota de corte” para entrar como alumno en la escuela de ingeniería industrial. using System; namespace ConsoleApplication3 { public class Alumno { double nota; public static double notaIngenieros=6; public Alumno(double nota) { this.nota=nota; } public bool estaAdmitido() { return (nota>=notaIngenieros); } public void ImprimirResultado(string nombre) { if(estaAdmitido()) Console.WriteLine("{0} está admitido",nombre); else Console.WriteLine("{0} no está admitido",nombre); } } class MiClase { static void Main(string[] args) { Alumno juan=new Alumno(6.5); Alumno jorge=new Alumno(5.2); Console.WriteLine("Nota de corte:{0}", Alumno.notaIngenieros); juan.ImprimirResultado("Juan"); jorge.ImprimirResultado("Jorge"); Console.WriteLine("\n"); Alumno.notaIngenieros=7; Console.WriteLine("Nota de corte:{0}", Alumno.notaIngenieros); juan.ImprimirResultado("Juan"); jorge.ImprimirResultado("Jorge"); } } 9/35 Marco Besteiro y Miguel Rodríguez Clases } La salida de este programa es: Nota de corte: 6 Juan está admitido

0 downloads 387 Views 126KB Size

Recommend Stories


Marco Besteiro y Miguel Rodríguez
Marco Besteiro y Miguel Rodríguez Atributos Attributes. El lenguaje C# permite al programador especificar información declarativa (atributos) de ent

PLAN MARCO CONJUNTO PARA LAS CLASES 8 a 12
PLAN MARCO CONJUNTO PARA LAS CLASES 8 a 12 COLEGIO HUMBOLDT CARACAS VENEZUELA Colegio Humboldt Caracas I. INTRODUCCIÓN I.1 PRÓLOGO El presente

Drogas: Clases y efectos
Ciencias sociales. Estimulantes. Relajantes. Alterantes. Disolventes. Pegamentos. Tabaco. Alcohol. Dependencia

Mercado y sus clases
Competencia perfecta e imperfecta. Monopolio. Oligopolio. Duopolio. Demanda esquinada

Story Transcript

Marco Besteiro y Miguel Rodríguez

Clases

Clases. Introducción La Programación Orientada a Objetos permite realizar grandes programas mediante la unión de elementos más simples, que pueden ser diseñados y comprobados de manera independiente del programa que va a usarlos. Muchos de estos elementos podrán ser reutilizados en otros programas. A estas “piezas”, “módulos” o "componentes", que interactúan entre sí cuando se ejecuta un programa, se les denomina objetos. Los objetos contienen datos y funciones que actúan sobre esos datos. Durante la ejecución de un programa, los objetos interactúan entre sí pasándose mensajes y devolviendo respuestas a estos mensajes. Es fundamental darse cuenta de que un objeto no necesita conocer el funcionamiento interno de los demás objetos para poder interactuar con ellos (igual que el hombre no necesita conocer cómo funciona el motor de su coche, el televisor o un ordenador para poder utilizarlos), sino que le es suficiente con saber la forma en que debe enviarle sus mensajes y cómo va a recibir la respuesta (al hombre le puede ser suficiente para utilizar el coche saber cómo conducir – acelerar, utilizar el volante, etc...-, cómo funcionan el interruptor, el dial del volumen y los botones de cambio de canal para utilizar un televisor, etc). Sucede a menudo que hay que utilizar varios ejemplares análogos de un determinado tipo (por ejemplo varias ventanas en la pantalla del PC, varios usuarios, varios clientes, varias cuentas corrientes de un banco, etc.). La definición genérica de estos objetos análogos se realiza mediante la clase. Así, una clase contiene una completa y detallada descripción de la información y de las funciones que contendrá cada objeto de esa clase. Los objetos son las variables concretas que se crean de una determinada clase. A veces se llaman también instancias. Así, se habla de crear un objeto o instancia de una clase. Las clases son verdaderos tipos de datos definidos por el usuario o por el sistema y pueden ser utilizados de igual manera que los tipos de datos simples, tales como int, float, etc. Un objeto tiene su propio conjunto de datos o variables miembro, aunque no de funciones, ya que las que se aplican a un objeto concreto son propias de la clase a la que pertenece el objeto. Para proteger a las variables de modificaciones no deseadas se introduce el concepto de encapsulación, ocultamiento o abstracción de datos. De ordinario una clase ofrece un conjunto de métodos públicos a través de los cuales se puede actuar sobre los datos, que serán privados. Estas funciones o métodos públicos constituyen la interfaz de la clase, es decir, el elemento que el programador puede utilizar para comunicarse con los objetos. . De esta forma se garantiza que se hace buen uso de los objetos, manteniendo la coherencia de la información. Esto sería imposible si se accediera libre e independientemente a cada variable miembro. Al usuario le es suficiente con saber 1/35

Marco Besteiro y Miguel Rodríguez

Clases

cómo comunicarse con un objeto, pero no tiene por qué conocer el funcionamiento interno del mismo. Se desea recalcar aquí que el concepto de interfaz es muy diferente al de interface, que se estudiará más adelante

Concepto de clase. Forma general Una clase sencilla Cuando se escribe un programa en un lenguaje orientado a objetos, se definen previamente las clases que van a describir las características y comportamiento de los objetos que se van a utilizar. Esto sucede de igual manera en C#. Una clase está compuesta por un conjunto de datos –llamados campos o variables miembro- y unos métodos que son funciones que operan sobre esos datos. El conjunto de campos y métodos de una clase constituyen sus miembros. El siguiente es un ejemplo de definición y declaración de una clase: public class Rectangulo { //variables miembro, datos o atributos int x; int y; private double ancho; private double largo; //funciones miembro o métodos public Rectángulo (double w, double h) { x = 0; y = 0; ancho = w; largo = h; } public double CalcularArea() { return ancho*largo; } }

Objetos Un objeto o instancia es un ejemplar concreto de una clase. En realidad, los objetos son variables de tipo clase. Es importante comprender muy bien la diferencia entre clase y objeto. Clase es la propia definición de un tipo de dato, realizada por el programador o proporcionada por el sistema. Es una abstracción lógica. Sin embargo, el objeto es un ejemplar de una clase, que tiene una existencia física ya que está físicamente en memoria, de la misma forma que una variable de un tipo valor es un ejemplar del tipo de la variable. Por ejemplo: 2/35

Marco Besteiro y Miguel Rodríguez

Clases

int unaVariable = 7;

En esta sentencia, el programador distingue perfectamente entre el tipo de dato –que es un entero, concepto o abstracción lógica- y la variable de ese tipo, que es un “ejemplar” de un entero, con una realidad física, almacenado en memoria y con un valor de 7. De igual forma, hay que distinguir entre clase –tipo de dato- y objeto –ejemplar de ese tipo de dato, de esa clase-. Para crear un objeto o instancia de una clase hay que dar dos pasos: a ) Crear una variable de tipo referencia que almacene la referencia al objeto. Por ejemplo, Rectángulo unRect;

En la sentencia anterior se reserva espacio en la pila o stack para la variable unRect que es una referencia a un objeto de la clase Rectángulo. Después de este paso, unRect no apunta a nada, no referencia ningún objeto. b ) Crear un objeto de la clase y asignarlo a la referencia anterior. unRect = new Rectángulo(5,7);

En la sentencia anterior, el operador new seguido de un constructor de la clase crea un objeto de la clase Rectángulo –es decir, reserva el espacio de memoria que sea necesario para un objeto de esa clase- y devuelve una referencia al objeto creado. El símbolo = asigna el objeto recién creado a la referencia unRect. El objeto se almacena en el heap o montón y la referencia en el stack o pila. Lo que se almacena en la variable no es el objeto en sí sino una referencia al objeto que ha sido creado previa asignación del bloque de memoria necesario. Es importante que el lector comprenda que esa variable unRect no es el objeto creado sino una referencia al mismo. El objeto se almacena en el montón.

Montón Pila

unRect Referencias a objetos de la clase Rectángulo doRect

3/35

x

0

y

0

ancho

5.0

largo

7.0

x

0

y

0

ancho

23.0

largo

347.0

Objetos

Marco Besteiro y Miguel Rodríguez

Clases

Figura 5.1 En la figura 5.1 puede verse dos referencias unRect y doRect a objetos de la clase Rectángulo. Habitualmente, estos dos pasos se reducen a uno sólo: Rectángulo unRect = new Rectángulo(5,7);

En la expresión anterior se crea una referencia unRect de tipo Rectángulo y se le asigna un objeto creado con el operador new. new crea el objeto físico, que es almacenado en memoria, el objeto, y unRect es una referencia a un objeto de tipo Rectángulo. El operador = asigna el objeto a la referencia. Aunque el objeto y la referencia son distintos, sin embargo es muy habitual hablar del objeto unRect en lugar de decir el objeto de la clase Rectangulo que está referenciado por unRect. Esta manera de hablar no produce ningún tipo de confusión y se utiliza con frecuencia.

Forma general de una clase Una clase es una estructura de datos que puede contener miembros dato (constantes, y campos, como x, y, ancho y largo), funciones miembro (métodos, propiedades, indexadores, eventos, operadores, constructores y destructores como CacularArea() y Rectángulo()) y tipos anidados. Las clases se declaran utilizando la palabra clave class. La estructura general de una clase es la siguiente: [atributos] [modificadores] class identificador [:lista-clases-base] { //cuerpo de la clase //Declaraciones de los miembros de la clase } Una declaración de clase consiste en un conjunto opcional de atributos –se estudiarán más adelante- seguidos por un conjunto también opcional de modificadores de clase, por la palabra reservada class y un identificador que da nombre a la clase. Realmente, la sintaxis es muy parecida a Java o C++. Después puede indicarse la clase base de la que deriva o/y las interfaces que implementa, separadas por comas. Por ejemplo class MiPrimeraClase { //Cuerpo de la clase }

En C# sólo se permite herencia simple, es decir, sólo puede heredarse desde una clase. Sin embargo, como en Java, se puede implementar más de una interface.

4/35

Marco Besteiro y Miguel Rodríguez

Clases

Los posibles modificadores que puede tener una clase son new, public, protected, internal, private, abstract y sealed. Los modificadores public, protected, internal y private son modificadores de control de acceso a la clase. Estos modificadores determinan la visibilidad de los miembros de una clase. Se realizará una explicación detallada de los modificadores, más adelante, en este mismo capítulo. Aunque se volverá a recalcar al hablar de los tipos de acceso, en este libro se seguirán la recomendaciones de Microsoft respecto a cómo escribir los nombres de los miembros de una clase. •

Se escriben con minúsculas los nombres de parámetros y campos privados o protegidos de una clase. Por ejemplo: private int unEntero; protected string cadena;



Los miembros públicos, las clases, etc, se escriben con mayúsculas. Por ejemplo: class MiClase{} namespace MiNamespace;



Las constantes con mayúsculas. Por ejemplo: public const double PI = 3.14;



Los nombre de una sóla letra con minúsculas: int x=8; private string s;

Los miembros de una clase pueden ser: • • • • • • • •

Constructores Destructores Constantes Campos Métodos Propiedades Indexadores Operadores

A continuación, se estudian cada uno de ellos.

Constantes y miembros de sólo lectura. Las constantes representan valores constantes asociados con la clase. El modificador const indica que un determinado campo es una constante y, por lo tanto, no puede ser modificada a lo largo del programa.

5/35

Marco Besteiro y Miguel Rodríguez

Clases

Por ejemplo: class Matemáticas { public const double PI=3.141592; }

Una constante es un valor que no puede ser cambiado y no se le puede asignar ningún valor. Por eso es imprescindible inicializarla en la propia clase. Esto significa que no podría haberse incluido en la clase anterior una línea como la siguiente: public

const double E;

Un campo de sólo lectura –readonly- es muy parecido a una constante pero proporciona un poco más de flexibilidad que una constante, ya que permite inicializarlo después –por ejemplo- de algún cálculo. En el siguiente ejemplo, se asigna un valor a un campo de este tipo en el constructor de la clase: class Personal { public readonly string password; public Personal(string unaPalabra) { password=unaPalabra; } }

Campos. Los campos de una clase almacenan información del objeto de la clase que se ha creado. Son aquéllas características que diferencian dos objetos de una misma clase y determinan su apariencia o estado. El acceso a los campos o miembros dato puede ser directo o bien a través de métodos o propiedades, dependiendo de la visibilidad de los campos –es decir, de los modificadores de cada variable. Los campos de un objeto se invocan con el operador punto (.). C# permite definir como campos tanto tipos valor como tipos referencia. En el primer caso, los objetos que se creen almacenarán una copia de las variables de tipo valor y en el segundo, una referencia a los objetos. También permite definir otra clase de miembros como propiedades, delegates, etc... Los campos de una clase se denominan a veces, campos o variables de instancia o de objeto en contraposición a las variables estáticas o de clase. Se llaman así porque cada instancia u objeto contiene su propia copia de cada campo o variable. Los datos de un objeto son propios y están separados –incluso físicamente- de los datos de otro objeto. Por esta razón, los cambios que se realicen en los campos de un objeto no afectan para nada a los campos de los demás objetos, aunque sean del mismo tipo de clase. Esto no sucede así con los campos de clase, porque todos los objetos comparten la misma variable físicamente. Por ejemplo: using System;

6/35

Marco Besteiro y Miguel Rodríguez

Clases

public class Rectangulo { //variables miembro, datos o atributos int x; int y; private double ancho; private double largo; //funciones miembro o métodos public Rectángulo (double w, double h) { x = 0; y = 0; ancho = w; largo = h; } public Set_Rectángulo(int x0,int y0,int w,int h) { x = x0; y = y0; ancho = w; largo = h; } public double CalcularArea() { return ancho*largo; } public void Imprimir() { Console.WriteLine(“Coordenadas: x={0}, y={1}”,x,y}; Console.WriteLine(“Ancho={0}, Largo={1}”,ancho,largo}; } } public static void Main() { Rectangulo unRect=new Rectangulo(55,44); unRect.Set_Rectangulo(10,15,100,58); unRect.Imprimir(); int area=unRect.CalcularArea(); Console.WriteLine(“Area={0}”,area); }

La salida de este programa es: Coordenadas: x = 10, y = 15 Ancho=100, Largo=58 Area=5800

Las variables de instancia se declaran en la clase pero sus valores se inicializan y cambian en los objetos. Además de las variables de instancia hay variables de clase. Se explicarán con detalle más adelante, en este mismo capítulo.

7/35

Marco Besteiro y Miguel Rodríguez

Clases

Métodos. Forma general Los métodos de una clase son porciones o bloques de código a los que los objetos de esa clase pueden llamar para que sean ejecutados. Generalmente operan sobre los campos. Las clases no tiene limitación en cuanto al número de métodos. Los métodos pueden tener parámetros y devolverlos. Si un método no devuelve nada, se utiliza la palabra void. La estructura general de un método es: [modificadores] tipo_de_retorno nombreDelMetodo (Parámetros_opcionales) { //cuerpo del método }

Los métodos de un determinado objeto se invocan con el operador punto (.). Todo método tiene que tener un nombre (nombreDelMetodo); ninguno, uno o varios parámetros con modificadores también opcionales; puede devolver cualquier tipo de dato u objeto (tipo_de_retorno), incluso los definidos por el programador; y unos modificadores opcionales. Aunque puede haber más, ahora se va a explicar únicamente los que definen método estáticos –static-.

Miembros estáticos Hay ocasiones en los que un miembro de una clase, ya sea campo o método, hace más referencia a la clase –es decir, a todos los objetos de la clase- que a cada objeto en concreto. Suponga –por ejemplo- que se desea llevar una cuenta del número de objetos de una determinada clase en un programa. C# proporciona un camino para crear un miembro que pueda utilizarse por sí mismo sin referirse a una instancia u objeto específico. Para ello, en su definición, el miembro ha de ir precedido por el modificador static. Cuando se declara un miembro como estático, se puede acceder a él sin haber creado ningún objeto en particular. Esto es lo que sucede con el método Main() que debe ser declarado como static porque tiene que ser invocado al inicio del programa, es decir, cuando todavía no se ha creado ningún objeto de ninguna clase. Al tener este modificador, el método Main() puede ser invocado sin necesidad de crear previamente ningún objeto. Los campos declarados como static son variables globales. Cuando se crean objetos de una clase que tiene un campo static, no se hace ninguna copia de él. Todos los objetos de esa clase comparten una única copia del mismo campo. Si uno de ellos lo modifica, quedará modificado para todos ellos. por esta razón, este tipo de miembros se denominan campos o métodos estáticos o de clase o , en contraposición a los métodos o campos de objeto o de instancia.

8/35

Marco Besteiro y Miguel Rodríguez

Clases

Fuera de la clase en la que han sido definidos, los métodos y campos estáticos se pueden utilizar independientemente de cualquier objeto. Únicamente es necesario especificar el nombre de la clase seguido del operador punto y del nombre del miembro, de la forma: NombreDeLaClase.metodoStatic( ); NombreDeLaClase.campoStatic;

A continuación se propone un ejemplo que puede servir para aclarar este concepto: Se trata de diseñar una clase Alumno en la cual se incluya la nota media para ingresar en la universidad y que tenga en cuenta la “nota de corte” para entrar como alumno en la escuela de ingeniería industrial. using System; namespace ConsoleApplication3 { public class Alumno { double nota; public static double notaIngenieros=6; public Alumno(double nota) { this.nota=nota; } public bool estaAdmitido() { return (nota>=notaIngenieros); } public void ImprimirResultado(string nombre) { if(estaAdmitido()) Console.WriteLine("{0} está admitido",nombre); else Console.WriteLine("{0} no está admitido",nombre); } } class MiClase { static void Main(string[] args) { Alumno juan=new Alumno(6.5); Alumno jorge=new Alumno(5.2); Console.WriteLine("Nota de corte:{0}", Alumno.notaIngenieros); juan.ImprimirResultado("Juan"); jorge.ImprimirResultado("Jorge"); Console.WriteLine("\n"); Alumno.notaIngenieros=7; Console.WriteLine("Nota de corte:{0}", Alumno.notaIngenieros); juan.ImprimirResultado("Juan"); jorge.ImprimirResultado("Jorge"); } }

9/35

Marco Besteiro y Miguel Rodríguez

Clases

}

La salida de este programa es: Nota de corte: 6 Juan está admitido Jorge no está admitido Nota de corte: 7 Juan no está admitido Jorge no está admitido

Puede verse que para llamar al miembro estático, al ser un miembro de clase, hay que invocarlo a través del nombre de la clase. En C# no puede llamarse a un método o campo estático a través del nombre del objeto –como en Java-, porque daría error. Así, notaIngenieros se manipula en la línea: Alumno.notaIngenieros=7;

Una vez ejecutada esta sentencia, el miembro estático cambia. Y lo hace en todos los objetos. Hay una sola copia de este miembro, aunque todos los objetos lo tengan y puedan utilizarlo. En este ejemplo, puede verse la diferencia entre un miembro de clase y uno de instancia, como nota. nota es diferente para cada alumno –cada objeto Alumno tiene su propia copia de su nota, y por ello, cambiar a un alumno la nota no modifica la nota del resto de los alumnos- mientras que notaCorteIngenieros tiene el mismo valor para todos los objetos o instancias. Los miembros estáticos deben inicializarse en la propia clase aunque si no se hace así, se inicializarán con los valores por defecto. Los métodos declarados como static tienen algunas restricciones: a) Sólo pueden llamar a métodos static. b) Solamente pueden acceder a campos static. c) No pueden referirse a this.

En resumen: aunque las clases se definen para poder crear objetos a partir de ella, una clase puede contar con miembros estáticos y ser usada directamente, sin crear objeto alguno. Mediante el uso de miembros estáticos es posible mantener información compartida entre todos los objetos de una clase. Dichos miembros no pertenecen a un objeto en particular, sino que son compartidos por todos. Por lo tanto, este miembro se crea con el primer objeto y es compartido por todos.

Modificadores de los parámetros Es en el paso de parámetros donde se registran las mayores diferencias con Java o C++. En C# hay cuatro alternativas para el paso de parámetros. Para identificar el tipo de paso, el parámetro va precedido en todos los casos excepto en uno, de una palabra

10/35

Marco Besteiro y Miguel Rodríguez

Clases

reservada. Dicha palabra se debe utilizar tanto en la definición del método como cuando se invoca al método. A continuación se van a estudiar las distintas posibilidades: •

Paso por valor: El método recibe una copia del valor almacenado en la variable original. En su código, el método trabaja con la copia -puede transformarla o modificarla- y pero no puede cambiar la variable original. Este es el único de los cuatro tipos de paso de parámetros que no se identifica por ninguna palabra reservada.

Por ejemplo: •

Paso por referencia: La palabra que identifica este tipo de paso de parámetros es ref. En este caso, al método se le pasa una referencia del objeto o la misma variable –no una copia-, de tal forma que cualquier modificación del objeto o variable se produce en el original porque se trabaja con ella. Por ejemplo •

Parámetro de salida: La palabra que precede al parámetro es out. Básicamente, es igual al paso por referencia, aunque en este caso el valor que se pasa al método no tiene ninguna importancia, porque ese parámetro va a ser utilizado realmente para devolver un dato o para asignarle un valor a una determinada variable u objeto. Es necesario asignar un valor al parámetro – en el cuerpo del método- antes de utilizarlo. En caso contrario el compilador generará una excepción. No se puede tampoco consultar antes de haberle asignado uno en el propio cuerpo del método. Por ejemplo: •

Listas variables de parámetros: La palabra que identifica este paso es params. params debe ir seguida del tipo de parámetro y los corchetes [] vacíos, que declaran que se desconoce el número de parámetros que se va a pasar. Si los parámetros no son del mismo tipo se usa el tipo object ya que todos los tipos son objetos. Por ejemplo

Control de acceso Un programador no necesita conocer el funcionamiento interno de una clase para utilizarla, de igual forma que para utilizar un coche no es necesario conocer el funcionamiento interno del motor y basta con saber cómo “comunicarse” con el coche – acelerar para aumentar la velocidad, girar el volante para cambiar de dirección, etc-. Le es suficiente con saber cómo utilizar un objeto de esa clase (es decir, cómo comunicarse con él) para utilizarlo. Para proteger a los miembros de una clase de modificaciones no deseadas y para garantizar que tomen valores lógicos y acordes con la naturaleza misma de los datos, se introduce el concepto de encapsulación de los datos. Por esta razón, los miembros de una clase van precedidos de un modificador que define la “visibilidad”, el modo de acceso al miembro de la clase.

11/35

Marco Besteiro y Miguel Rodríguez

Clases

En líneas muy generales, se puede decir que la encapsulación consiste en definir los campos de datos como privados para protegerlos y los métodos como públicos para que puedan manipular los datos. En general, la encapsulación es una manera común de escribir el código de una clase. Se mantienen los datos ocultos al exterior de la clase para que no se puedan utilizar desde el exterior y se escriben una serie de miembros públicos –que pueden manipular cualquier campo de esa clase- que permitan al programador manipular esos datos –o algunos datos- desde el exterior, desde su programa. En general, el interfaz –no el interface- de una clase está constituido por el conjunto de métodos públicos de una clase y es el medio por el que el programador puede “comunicarse” con los objetos de esa clase: puede modificar y manipular los datos, cambiar sus campos, enviarle mensajes, etc. No es necesario que el programador tenga acceso a los detalles de implementación de la clase. Le es suficiente con conocer cómo se utilizan los métodos públicos: qué mensajes se pueden enviar al objeto a través de ellos, y cómo responden los objetos a un determinado mensaje, es decir, qué devuelven. En resumen, le basta con conocer el interfaz de la clase.. Los modificadores de acceso a los miembros de una clase permiten ocultar, proteger y encapsular los datos de una clase. Aunque posteriormente se hablará del resto de los modificadores, ahora se explica el acceso a los miembros públicos y privados de una clase. Un miembro que no tiene un modificador de acceso es, por defecto, private. Por ejemplo: public class UnaClase { int a; private int b; public int c; public void Imprimir() { Console.WriteLine("a={0}, b={1},C={2}",a,b,C); } } class MiAplicacion { static void Main(string[] args) { UnaClase clase=new UnaClase(); //Los objetos de UnaClase no pueden acceder //a los miembros privados de UnaClase. //las dos siguientes líneas darán error al compilar clase.a = 10; clase.b = 11; //Los objetos de UnaClase pueden acceder //a los miembros públicos de UnaClase. //Solo se puede llamar desde el exterior de una clase //a sus miembros publicos clase.c = 12; clase.Imprimir();

12/35

Marco Besteiro y Miguel Rodríguez

Clases

} }

Las líneas clase.a = 10; clase.b = 11;

no pueden compilarse –deben ser comentadas para que el proceso de compilación las omita- porque no se puede invocar un miembro privado desde el exterior de la propia clase; ni siquiera los objetos de la clase UnaClase pueden hacerlo. Esos miembros sólo se pueden manipular, invocar o llamar desde el mismo código de definición de la clase. Se puede decir que las funciones miembro de la clase UnaClase pueden acceder a miembros públicos y privados de la clase. Los objetos de la clase UnaClase pueden acceder sólo a miembros públicos de UnaClase, como puede verse en las siguientes líneas: clase.c = 12; clase.Imprimir();

Sin embargo los miembros de la clase pueden acceder a los miembros públicos y privados de la clase, pero siempre desde el interior –desde el propio código de definición- de la clase. Por ejemplo, vemos que el método Imprimir() puede acceder sin problemas a los miembros de la clase. La salida del programa es a=0,b=0, c=12;

Sobrecarga de métodos Muchas veces se ha utilizado en este libro la sobrecarga de métodos pero sin decirlo explícitamente. Por ejemplo, para imprimir en pantalla un valor entero, se puede hacer algo parecido a: int x = 6; Console.WriteLine(x};

Si se desea imprimir una cadena, el código puede ser: String unaCadena = “Hola Mundo”; Console.WriteLine(unaCadena};

¿Cómo es esto posible? ¿Porqué el método Console.WriteLine() toma dos parámetros de tipo distinto? Si el método espera un string en el primero de los casos generaría un error al compilar porque no se realiza un casting implícitamente de int a string. Es parecido lo que ocurriría en el segundo de los casos. La explicación es que hay dos métodos diferentes de nombre Console.WriteLine(), uno de los cuales toma como parámetro un entero y el otro una cadena. Incluso, se puede utilizar este método con un número de parámetros diferente. Por ejemplo: 13/35

Marco Besteiro y Miguel Rodríguez

Clases

String unaCadena = “Hola Mundo”; Console.WriteLine(“La cadena es {0,}”,unaCadena};

En C#, como en otros lenguajes de programación orientada a objetos, se puede sobrecargar métodos. La sobrecarga de métodos consiste en declarar y definir varios métodos distintos con el mismo nombre. Cada uno de estos métodos se define de forma diferente. En el momento de la ejecución el compilador llama a uno u otro dependiendo del tipo de los argumentos del método y/o del número de parámetros que se utilizan. Por ejemplo, se puede definir varias funciones para calcular el valor absoluto de una variable, todas con el mismo nombre pero cada una con un argumento diferente y devolviendo un valor distinto. Para sobrecargar un método es necesario que los dos métodos difieran al menos en el tipo de alguno de sus argumentos o en el número de ellos. No basta con que tengan valores de retorno diferentes. Por ejemplo: using System; namespace Sobrecarga { class UnaAplicacion { public static int Abs(int n) { if(n>=0) return n; else return -n; } public static double Abs(double d) { if(d>=0) return d; else return -d; } static void Main(string[] args) { int unEntero=-2; double unDouble=3.34;

Console.WriteLine("Abs({0})={1}",unEntero,Abs(unEntero)); Console.WriteLine("Abs({0})={1}",unDouble,Abs(unDouble)); } } }

La salida de este programa es: Abs(-2) = 2 Abs(3.34) = 3.34

14/35

Marco Besteiro y Miguel Rodríguez

Clases

En este ejemplo se observa cómo el compilador puede distinguir el código que debe utilizar porque el tipo de argumento es diferente en los dos métodos. En el siguiente ejemplo, el compilador puede distinguirlos porque el número de argumentos que utiliza en las llamadas es diferente –aunque en este caso también el tipo-. using System; namespace UnNamespace { public class MiClaseApp { public static void Imprimir(string str) { Console.WriteLine("La cadena es {0}",str); } public static void Imprimir(int x, double y) { Console.WriteLine("x={0},y={1}",x,y); } static void Main(string[] args) { int x=8; double y=9.34; string unaCadena="Hola Mundo"; Imprimir(x,y); Imprimir(unaCadena); } } }

La salida de este programa es : x=8, y=9.34 La cadena es Hola Mundo

Como se verá más adelante, los operadores se pueden también sobrecargar, aunque tienen una estructura un poco diferente a la sobrecarga de métodos.

Constructores. El constructor es un método especial que permite inicializar un objeto de una clase en el momento que éste se está creando. Es decir, da unos valores iniciales a los distintos campos del objeto en el momento en que se crea. Un constructor debe: a) Tener el mismo nombre de la clase b) Ser público c) No tener ningún retorno –ni siquiera void-. Realmente, lo que ocurre es que inmediatamente después de que se crea el objeto, el compilador invoca al constructor. El funcionamiento es igual que un método. En el ejemplo de la clase Rectángulo, ya se ha utilizado un constructor de la clase. public Rectángulo (double w, double h) {

15/35

Marco Besteiro y Miguel Rodríguez

Clases

x = 0; y = 0; ancho = w; largo = h; }

Para crear un objeto de la clase Rectangulo se utilizaba la instrucción: Rectangulo unRect = new Rectangulo(55,44);

Esta sentencia, después de reservar memoria para el objeto –para cada uno de sus campos- ejecuta el código del constructor. Inicializa los campos x, y, ancho y largo con los valores 0,0, 55 y 44 respectivamente. Además se puede distinguir entre los constructores de instancia y los constructores estáticos (static). Los constructores de instancia implementan las acciones necesarias para inicializar las instancias de la clase, es decir, los objetos. Los constructores estáticos (static): implementan las acciones necesarias para inicializar la clase en sí.

Sobrecarga de un constructor Un constructor puede estar sobrecargado. De esta manera se proporciona una gran flexibilidad a la hora de inicializar los objetos de una clase cualquiera. La sobrecarga de un constructor es muy parecida a la sobrecarga de un método. Se puede escribir para una clase tantos constructores como se desee. Sin embargo, los constructores deben diferenciarse entre sí o en el número de parámetros o al menos, en el tipo de parámetro. El compilador en tiempo de ejecución diferenciará entre ellos y utilizará el que se ajuste en número y tipo al constructor que se utilice en el programa. En el siguiente ejemplo se ilustra esta idea: using System; namespace Matematicas { class Rectangulo { int x0; int y0; int ancho; int largo; public Rectangulo() { x0=y0=0; ancho=10; largo=10; } public Rectangulo(int x0,int y0,int ancho,int largo) { this.x0=x0;

16/35

Marco Besteiro y Miguel Rodríguez

Clases

this.y0=y0; this.ancho=ancho; this.largo=largo; } public Rectangulo(int ancho,int largo) { x0=0; y0=0; this.ancho=ancho; this.largo=largo; } public Rectangulo(int lado) { x0=0; y0=0; ancho=lado; largo=lado; } public void Imprimir(string nombreDelRectangulo) { Console.WriteLine("Datos del Rectangulo{0}" ,nombreDelRectangulo); Console.WriteLine("x0={0},y0={1},ancho={2},largo={3}" ,x0,y0,ancho,largo); Console.WriteLine(); } } class ClaseApp { static void Main(string[] args) { Rectangulo rect1=new Rectangulo(); rect1.Imprimir("Primer Rectangulo"); Rectangulo rect2=new Rectangulo(100); rect1.Imprimir("Segundo Rectangulo"); Rectangulo rect3=new Rectangulo(100,200); rect1.Imprimir("Tercer Rectangulo"); Rectangulo rect4=new Rectangulo(20,30,200,400); rect1.Imprimir("Cuarto Rectangulo"); } } }

La salida de este programa es:

17/35

Marco Besteiro y Miguel Rodríguez

Clases

Figura 5.2 Hay que tener en cuenta que si se define un constructor cualquiera para una clase, el constructor por defecto queda anulado. Así, en el anterior ejemplo no hubiera sido posible utilizar Rectángulo() si no se hubiera sobrecargado.

Inicialización de miembros por defecto Si no se define ningún constructor, el compilador define un constructor denominado constructor por defecto. Dicho constructor no tiene código ni parámetros. Su única misión es inicializar cada uno de los campos con sus valores por defecto. Dichos valores dependen del tipo de dato con el que se esté trabajando. Las inicializaciones por defecto para los distintos tipos es la siguiente:

-

-

Para todos los tipos simples, el valor por defecto es 0. - Para sbyte, byte, short, ushort, int, uint, long, y ulong, el valor por defecto es 0. - Para char, el valor por defecto es '\x0000' - Para float, el valor por defecto es 0.0f. - Para double, el valor por defecto es 0.0d. - Para decimal, el valor por defecto es 0.0m. - Para bool, el valor por defecto es false. Para un tipo enum, el valor por defecto es 0. Para un tipo struct, al igual que la clase, el valor por defecto es el resultado de dar el valor por defecto a todos sus campos. Por ejemplo:

using System; public class Persona {

18/35

Marco Besteiro y Miguel Rodríguez

Clases

private int edad; private string nombre; // Constructor por defecto public Persona () { nombre = "N/A"; } // Constructor public Persona (string nombre, int edad) { this.nombre = nombre; this.edad = edad; } public void Imprimir() { Console.WriteLine("{0} tiene {1} años.", nombre, edad); } } public class UnaAplicacion { public static void Main() { // Se crean los objetos // Se deben crear utilizando el operador new: Persona persona1 = new Persona ("Patricia", 11); Persona persona2 = new Persona ("Maria", 10); // Crea un objeto utilizando el constructor por defecto: Persona persona3 = new Persona (); // Imprimimos los resultados: Console.Write("Persona #1: "); persona1.Imprimir (); Console.Write("Persona #2: "); persona2.Imprimir (); Console.Write("Persona #3: "); persona3.Imprimir (); } }

Referencia this Si una variable local tiene el mismo nombre que un miembro de una clase entonces lo oculta. Para estas ocasiones, o para otras en la que por diversas circunstancias interesa referirse en el código de una clase al propio objeto, se utiliza this, que es una referencia implícita al propio objeto. Por ejemplo: class Rectángulo { int ancho; int largo; public Rectángulo(int ancho, int largo)

19/35

Marco Besteiro y Miguel Rodríguez

Clases

{ this.ancho=ancho; this.largo=largo; } }

En este ejemplo, los parámetros ancho y largo del constructor ocultan los campos de la propia clase porque tienen el mismo nombre. Para evitar este problema y que muchas veces permite que el código sea más legible, se utiliza this.

Destructores y recolector de basura. Los destructores contienen el código que se ha de ejecutar cuando se destruye un objeto, una instancia de una clase. Su forma general es: [atributosopt] ~ nombreDeLaClase( ) { //Codigo }

Los atributos son opcionales. El nombre debe coincidir con el de la clase, pero debe ir precedido del símbolo ~ (ALT+126) El funcionamiento de los destructores no se parece al de C++. Realmente, es el código que se ejecuta cuando un objeto se destruye. Es muy parecido al método finalize de Java. El destructor es llamado por el recolector de basura cuando el objeto va a ser destruido. De hecho es un alias del método finalize. Se mantiene por comodidad al migrar.

Propiedades. Las propiedades constituyen una importante aportación de C# y de uno de los autores de este lenguaje, Anders Hejlsberg. Probablemente, algunos lectores que hayan utilizado Delphi o C++ Builder de Borland, el concepto de propiedad les resultará familiar, ya que Hejlsberg es el diseñador de la VCL que es la librería en la que se apoyan estos dos estupendas herramientas visuales de programación. Las propiedades permiten acceder a los campos privados de una clase de una manera controlada y sencilla. Esto resulta especialmente útil, ya que es importante no permitir que un determinado campo pueda adquirir valores no deseados. Además, las propiedades permiten dotar a los campos de la característica de ser de lectura o escritura únicamente. Las propiedades definen atributos con nombre (campos, realmente) y las acciones asociadas con la lectura y escritura de esos atributos. Antes de proseguir con el concepto de propiedad, es importante que el lector comprenda bien los dos procesos distintos –accesos- que pueden llevarse a cabo en un campo de una clase: el proceso de lectura y el proceso de escritura.

20/35

Marco Besteiro y Miguel Rodríguez

Clases

Por ejemplo: using System; namespace Propiedades { class Rectangulo { public int Ancho; public int Largo; } class MiAplicacion { static void Main(string[] args) { Rectangulo unRect=new Rectangulo(); unRect.Ancho=10; unRect.Largo=25; Console.WriteLine("Ancho={0}, Largo={1}",unRect.Ancho,unRect.Largo); } } }

En este programa se puede observar cómo se asignan valores –10 y 25- a los campos públicos Ancho y Largo del objeto unRect. La asignación se puede considerar como un proceso de escritura en el campo. Sin embargo, en la sentencia en la que se imprimen los datos se está consultando un campo o en un proceso de lectura del campo. En este ejemplo se han considerado dos campos públicos para ganar en sencillez. Sin embargo y como ya se ha explicado en varias ocasiones no es lo ideal, porque los campos deben tener un acceso restringido, tanto de lectura como de escritura. Piense el lector, por ejemplo, si se hubiera dado una de las dos dimensiones con un valor negativo. No tendría sentido. El hecho de controlar los procesos de lectura y escritura es muy importante. Se puede hacer escribiendo métodos apropiados y de hecho, en los lenguajes orientados a objetos se venía haciendo así hasta ahora. Sin embargo, esto puede ser, en ocasiones, tedioso. Las propiedades constituyen una manera fácil y elegante de hacerlo. La declaración de una propiedad consta de una parte donde se define el proceso de lectura –denominado acceso get- y otra en la que se define el proceso de escritura o acceso set. El acceso get contiene el código que se ha de ejecutar en la consulta o lectura de la propiedad y por lo tanto del campo. Debe terminar siempre con la sentencia return o throw. Además el flujo de control no puede salir del cuerpo del acceso. Por ejemplo: private string nombre; public string Nombre { get

// Campo nombre // Propiedad Nombre

21/35

Marco Besteiro y Miguel Rodríguez

Clases

{ return nombre; } }

Para utilizarlo: Persona unaPersona = new Persona(); ... Console.Write(unaPersona.Nombre); // Se invoca el acceso get.

El acceso set contiene el código que se ha de ejecutar al escribir en la propiedad y por lo tanto en un campo. El parámetro value es el valor que se le da a la propiedad. Generalmente en este campo se suele implementar el código de validación de acceso a la propiedad. Ejemplo: public string Nombre { get { return nombre; } set { nombre = value; } }

Un uso posible es, por ejemplo: unaPersona.Nombre = "Macarena";

// Se invoca el acceso set

Ahora se adjunta un ejemplo completo: using System; namespace Propiedades { class Rectangulo { int ancho; int largo; public Rectangulo(int w, int h) { ancho=w; largo=h; } public int Ancho { get { return ancho; } set {

22/35

Marco Besteiro y Miguel Rodríguez

Clases

if(value < >=

Get in touch

Social

© Copyright 2013 - 2024 MYDOKUMENT.COM - All rights reserved.