AnteriorPosterior

6.2. Objetos y clases en C#

  Curso: Programación en C# (2015), por Nacho Cabanes

6.2. Objetos y clases en C#

Las clases en C# se definen de forma parecida a los registros (struct), sólo que ahora, además de variables (que representan sus detalles internos, y que llamaremos sus "atributos"), también incluirán funciones (las acciones que puede realizar ese objeto, que llamaremos sus "métodos"). Atributos y métodos formarán parte de "un todo", en vez de estar separados en distintas partes del programa. Esto es lo que se conoce como "Encapsulación".

Así, una clase "Puerta" se podría declarar así:

public class Puerta
{
 
    int ancho;     // Ancho en centimetros
    int alto;      // Alto en centimetros
    int color;     // Color en formato RGB
    bool abierta;  // Abierta o cerrada
 
    public void Abrir() 
    {
        abierta = true;
    }
 
    public void Cerrar() 
    {
        abierta = false;
    }
 
    public void MostrarEstado() 
    {
        Console.WriteLine("Ancho: {0}", ancho);
        Console.WriteLine("Alto: {0}", alto);
        Console.WriteLine("Color: {0}", color);
        Console.WriteLine("Abierta: {0}", abierta);
    }
 
} // Final de la clase Puerta   
 

Como se puede observar, los objetos de la clase "Puerta" tendrán un ancho, un alto, un color, y un estado (abierta o no abierta), y además se podrán abrir o cerrar (y además, nos pueden "mostrar su estado", para comprobar que todo funciona correctamente).

Para declarar estos objetos que pertenecen a la clase "Puerta", usaremos la palabra "new", igual que hacíamos con los "arrays":

ejemplo = new int[4];

Cuando sepamos cuantos datos vamos a guardar (por ejemplo 4), podremos reservar espacio con la orden "new", así:

Puerta p = new Puerta();
p.Abrir();
p.MostrarEstado();

Vamos a completar un programa de prueba que use un objeto de esta clase (una "Puerta"), muestre su estado, la abra y vuelva a mostrar su estado:

// Ejemplo_06_02a.cs
// Primer ejemplo de clases
// Introducción a C#, por Nacho Cabanes
 
using System;
 
public class Puerta
{
 
    int ancho;     // Ancho en centimetros
    int alto;      // Alto en centimetros
    int color;     // Color en formato RGB
    bool abierta;  // Abierta o cerrada
 
    public void Abrir() 
    {
        abierta = true;
    }
 
    public void Cerrar() 
    {
        abierta = false;
    }
 
    public void MostrarEstado() 
    {
        Console.WriteLine("Ancho: {0}", ancho);
        Console.WriteLine("Alto: {0}", alto);
        Console.WriteLine("Color: {0}", color);
        Console.WriteLine("Abierta: {0}", abierta);
    }
 
} // Final de la clase Puerta   
 
 
public class Ejemplo_06_02a
{
 
    public static void Main()
    {
        Puerta p = new Puerta();
 
        Console.WriteLine("Valores iniciales...");
        p.MostrarEstado();
 
        Console.WriteLine();
 
        Console.WriteLine("Vamos a abrir...");
        p.Abrir();
        p.MostrarEstado();
    }
 
}
 

Este fuente ya no contiene una única clase (class), como todos nuestros ejemplos anteriores, sino dos clases distintas:

  • La clase "Puerta", que es el nuevo objetos con el que vamos a practicar.
  • La clase "Ejemplo_06_02a", que representa a nuestra aplicación.

(Nota: al compilar, puede que obtengas algún "Aviso" -warning- que te dice que has declarado "alto", "ancho" y "color", pero no las estás utilizando; no es importante por ahora, puedes ignorar ese aviso).

El resultado de ese programa es el siguiente:

Valores iniciales...
Ancho: 0
Alto: 0
Color: 0
Abierta: False
 
Vamos a abrir...
Ancho: 0
Alto: 0
Color: 0
Abierta: True

Se puede ver que en C# (pero no en todos los lenguajes), las variables que forman parte de una clase (los "atributos") tienen un valor inicial predefinido: 0 para los números, una cadena vacía para las cadenas de texto, "false" para los datos booleanos.

Vemos también que se accede a los métodos y a los datos precediendo el nombre de cada uno por el nombre de la variable y por un punto, como hacíamos con los registros (struct).

Aun así, en nuestro caso no podemos hacer directamente "p.abierta = true" desde el programa principal, por dos motivos:

  • El atributo "abierta" no tiene delante la palabra "public"; por lo que no es público, sino privado, y no será accesible desde otras clases (en nuestro caso, no lo será desde Ejemplo_06_02a).
  • Los puristas de la Programación Orientada a Objetos recomiendan que no se acceda directamente a los atributos, sino que siempre se modifiquen usando métodos auxiliares (por ejemplo, nuestro "Abrir"), y que se lea su valor también usando una función. Esto es lo que se conoce como "ocultación de datos". Supondrá ventajas como que podremos cambiar los detalles internos de nuestra clase sin que afecte a su uso.

Por ejemplo, para conocer y modificar los valores del "ancho" de una puerta, podríamos crear un método LeerAncho, que nos devolviera su valor, y un método CambiarAncho, que lo reemplazase por otro valor. No hay un convenio claro sobre cómo llamar a a estos métodos en español, por lo que es frecuente usar las palabras inglesas "Get" y "Set" para leer y cambiar un valor, respectivamente. Así, crearemos funciones auxiliares GetXXX y SetXXX que permitan acceder al valor de los atributos (en C# existe una forma alternativa de hacerlo, usando "propiedades", que veremos más adelante):

public int GetAncho() 
{
    return ancho;
}
 
public void SetAncho(int nuevoValor) 
{
    ancho = nuevoValor;
}

Así, una nueva versión del programa, que incluya ejemplos de Get y Set, podría ser:

// Ejemplo_06_02b.cs
// Clases, get y set
// Introducción a C#, por Nacho Cabanes
 
using System;
 
public class Puerta
{
 
    int ancho;     // Ancho en centimetros
    int alto;      // Alto en centimetros
    int color;     // Color en formato RGB
    bool abierta;  // Abierta o cerrada
 
    public void Abrir() 
    {
        abierta = true;
    }
 
    public void Cerrar() 
    {
        abierta = false;
    }
 
    public int GetAncho() 
    {
        return ancho;
    }
 
    public void SetAncho(int nuevoValor) 
    {
        ancho = nuevoValor;
    }
 
    public void MostrarEstado() 
    {
        Console.WriteLine("Ancho: {0}", ancho);
        Console.WriteLine("Alto: {0}", alto);
        Console.WriteLine("Color: {0}", color);
        Console.WriteLine("Abierta: {0}", abierta);
    }
 
} // Final de la clase Puerta   
 
public class Ejemplo_06_02b
{
 
    public static void Main()
    {
        Puerta p = new Puerta();
 
        Console.WriteLine("Valores iniciales...");
        p.MostrarEstado();
 
        Console.WriteLine();
 
        Console.WriteLine("Vamos a abrir...");
        p.Abrir();
        p.SetAncho(80);
        p.MostrarEstado();
    }
 
}
 

También puede desconcertar que en "Main" aparezca la palabra "static", mientras que no lo hace en los métodos de la clase "Puerta". Veremos el motivo un poco más adelante, pero de momento perderemos la costumbre de escribir "static" antes de cada función: a partir de ahora, sólo Main será "static".

Ejercicios propuestos:

Ejercicio propuesto 6.2.1: Crea una clase llamada Persona, en el fichero "persona.cs". Esta clase deberá tener un atributo "nombre", de tipo string. También deberá tener un método "SetNombre", de tipo void y con un parámetro string, que permita cambiar el valor del nombre. Finalmente, también tendrá un método "Saludar", que escribirá en pantalla "Hola, soy " seguido de su nombre. Crea también una clase llamada PruebaPersona. Esta clase deberá contener sólo la función Main, que creará dos objetos de tipo Persona, les asignará un nombre a cada uno y les pedirá que saluden.
Ejercicio propuesto 6.2.2: Tras leer la descripción de Space Invaders que vimos en el apartado anterior, crea una clase Juego,que sólo contenga un método Lanzar, void, sin parámetros, que escriba en pantalla "Bienvenido a Console Invaders. Pulse Intro para salir" y se parará hasta que el usuario pulse Intro. Prepara también un Main (en la misma clase), que cree un objeto de la clase juego y lo lance.
Ejercicio propuesto 6.2.3: Para guardar información sobre libros, vamos a comenzar por crear una clase "Libro", que contendrá atributos "autor", "titulo", "ubicacion" (todos ellos strings) y métodos Get y Set adecuados para leer su valor y cambiarlo. Prepara también un Main (en la misma clase), que cree un objeto de la clase Libro, dé valores a sus tres atributos y luego los muestre.
Ejercicio propuesto 6.2.4: Crea una clase "Coche", con atributos "marca" (texto), "modelo" (texto), "cilindrada" (número entero), potencia (número real). No hace falta que crees un Main de prueba.

Actualizado el: 28-01-2015 14:16

AnteriorPosterior