Ir al contenido
wannacode

Clases y objetos

En resumen: Una clase describe un tipo nuevo con campos, y un objeto es una instancia concreta de ella, creada con new; la variable solo apunta al objeto.

Problema

Los precios se mezclaron

Estás escribiendo el carrito de una tienda en línea. Cada producto tiene un nombre y un precio, así que los guardas en dos arrays. El índice 0 guarda el nombre y el precio del primer producto, el índice 1 los del segundo.

Quieres el más caro primero, así que intercambias los precios:

string[] names = { "Pan", "Leche", "Café" };
double[] prices = { 1.20, 2.10, 7.50 };
// Lo más caro primero: intercambiamos el primer y el tercer precio.
double temp = prices[0];
prices[0] = prices[2];
prices[2] = temp;
for (int i = 0; i < names.Length; i++)
{
Console.WriteLine(names[i] + ": " + prices[i] + " €");
}
Salida
Pan: 7.5 €
Leche: 2.1 €
Café: 1.2 €

Ahora el pan cuesta 7,50 €. Los precios se intercambiaron, pero los nombres no. Los dos arrays siempre tienen que cambiar juntos, pero nada te obliga a hacerlo. Añade un tercer array para las cantidades, y tendrás que vigilar tres.

La idea

Un producto, un lugar

El nombre y el precio no son cosas separadas. Son partes de un producto. Queremos un tipo «producto», igual que existe int para los números y string para el texto.

Un tipo así lo creas tú mismo. Se llama clase:

class Product
{
public string Name;
public double Price;
public int Quantity;
}

Las variables de la clase son sus campos. Cada producto tendrá su propio nombre, su propio precio y su propia cantidad.

La clase es solo una descripción: «cada producto tiene un nombre, un precio y una cantidad». Todavía no hay ningún producto.

public significa que los campos también se ven desde fuera, desde Main. Sin él, C# no los muestra fuera. Verás por qué en la lección «Encapsulamiento». En C#, los nombres de los campos públicos empiezan con mayúscula: Name, Price.

La idea

new: de la descripción a un producto

Creas un producto concreto a partir de la clase con new. Se llama objeto. Llegas a sus campos con un punto:

Program.cs
class Product
{
public string Name;
public double Price;
public int Quantity;
}
class Program
{
static void Main()
{
Product bread = new Product();
bread.Name = "Pan";
bread.Price = 1.20;
bread.Quantity = 2;
Product coffee = new Product();
coffee.Name = "Café";
coffee.Price = 7.50;
coffee.Quantity = 1;
Console.WriteLine(bread.Name + ": " + bread.Price * bread.Quantity + " €");
Console.WriteLine(coffee.Name + ": " + coffee.Price * coffee.Quantity + " €");
}
}
Salida
Pan: 2.4 €
Café: 7.5 €
  • La clase está fuera de class Program, encima. Un archivo puede tener varias clases.
  • Product bread es una variable de tipo Product, igual que int count es de tipo int.
  • new Product() crea un objeto nuevo. Cada objeto tiene sus propios campos: el pan y el café no se estorban.
  • bread.Price es «el precio del pan». Lo lees y lo escribes como una variable normal.

Ahora el nombre y el precio del producto están en un solo lugar. Mueves el producto, y se mueven juntos.

Pruébalo

No se ha rellenado nada

Si creas un producto y no rellenas nada, ¿qué hay en sus campos?

¿Qué imprimirá el programa?

Product item = new Product();
Console.WriteLine(item.Name);
Console.WriteLine(item.Price);
Console.WriteLine(item.Quantity);
Respuesta

Pruébalo

¿Qué falta?

¿Qué va en el hueco para que haya un producto nuevo?

Product milk =  Product();
milk.Name = "Leche";
milk.Price = 2.10;

Míralo

La variable apunta al objeto

Quieres una oferta de café, así que haces una «copia» para cambiarle el precio:

Product coffee = new Product();
coffee.Price = 10;
Product sale = coffee;
sale.Price = 8;
Console.WriteLine(coffee.Price); // 8
Paso a paso, en palabras
  1. new crea el objeto, y sus campos reciben valores iniciales. coffee recibe una flecha hacia él.
  2. Por la flecha de coffee: el precio del objeto pasa a ser 10.
  3. sale = coffee copia la flecha, no el objeto. Dos flechas, un objeto.
  4. Por la flecha de sale: el precio del mismo objeto pasa a ser 8.
  5. coffee apunta al mismo objeto, así que imprime 8.

El precio del café también pasó a ser 8. La razón es que la variable coffee no es el objeto en sí. El objeto vive aparte en la memoria, y coffee guarda dónde está: una flecha al objeto. Una variable así se llama referencia.

sale = coffee copia la flecha, no el objeto. Ahora dos flechas apuntan a un objeto, así que el cambio a través de sale se ve también a través de coffee.

Ya viste lo mismo en la lección sobre arrays: sale = prices le daba un segundo nombre al mismo array. Un array también es un objeto.

La idea

Ahora el descuento funciona

En el módulo «Métodos», el descuento no funcionaba: el método recibía una copia del precio, cambiaba la copia, y la copia se perdía. Con un objeto es distinto:

static void Discount(Product p, double percent)
{
p.Price = p.Price * (100 - percent) / 100;
}
Product coffee = new Product();
coffee.Price = 10;
Discount(coffee, 10);
Console.WriteLine(coffee.Price);
Salida
9

El parámetro sigue siendo una copia, pero una copia de la flecha. Apunta al mismo objeto, así que el cambio de p.Price se queda también después del método.

Más precisamente, para curiosos

Si el método pone un objeto nuevo en el parámetro, solo mueve su propia copia de la flecha. El objeto de fuera no cambia:

static void Reset(Product p)
{
p = new Product();
p.Price = 0;
}
Product coffee = new Product();
coffee.Price = 10;
Reset(coffee);
Console.WriteLine(coffee.Price);
Salida
10
Por eso se dice que C# pasa por valor (salvo con ref y out), y para los objetos el valor es la referencia.

La idea

null: una flecha a ninguna parte

Una variable de un tipo clase puede no apuntar a nada. Entonces guarda null. Si intentas leer un campo a través de ella, no hay ningún objeto del que leerlo:

Product gift = null;
Console.WriteLine(gift.Name);

El programa compila, pero se detiene con un error cuando llega a la línea:

Error
Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.

Es el error más común con objetos. Qué es una «excepción» y cómo se captura, lo verás en el módulo «Errores y excepciones».

Cuidado con los arrays de objetos. new Product[3] crea tres lugares para flechas, no tres productos. Cada uno es null hasta que pones ahí new Product():

Product[] cart = new Product[3];
Console.WriteLine(cart[0] == null);
cart[0] = new Product();
cart[0].Name = "Pan";
Console.WriteLine(cart[0].Name);
Salida
True
Pan

Pruébalo

Encuentra el error

El programa debería imprimir «Pan» y «Leche». En cambio, imprime «Leche» dos veces. ¿Qué línea tiene el error?

Elige la línea con el error.

Ejercicio

Tus clases

Resuelve las tareas en tu editor. La clase va encima de class Program, y los objetos los creas en Main.

1. Libro. Una clase Book con campos para el título y el autor. Crea dos libros e imprímelos.

Salida
Cien años de soledad de Gabriel García Márquez
Rayuela de Julio Cortázar

2. Coche. Una clase SimpleCar con un campo para la velocidad. Crea un coche (su velocidad es 0), aumenta la velocidad en 10 e imprímela. En la lección «Métodos de instancia» esto se convertirá en un método del coche.

Salida
Velocidad tras acelerar: 10

3. El carrito. El carrito de la primera tarjeta, esta vez con un array de tres objetos Product: pan 1,20 € (2 uds.), leche 2,10 € (1 ud.), café 7,50 € (1 ud.). Imprime el importe de cada línea y el total. Recuerda que después de new Product[3] todavía no hay productos en el array.

Salida
Pan x2: 2.4 €
Leche x1: 2.1 €
Café x1: 7.5 €
Total: 12 €

4. El más caro primero. Ordena el mismo carrito por precio, del más caro al más barato, con el ordenamiento de burbuja de la lección sobre arrays. Esta vez intercambias productos enteros, así que el nombre y el precio se mueven juntos.

Salida
Café: 7.5 €
Leche: 2.1 €
Pan: 1.2 €

Más tareas

  • Estudiante. Una clase Student con un nombre y tres notas (tres campos). Crea dos estudiantes e imprime la nota media de cada uno.
  • Un libro, dos nombres. Crea un libro, guárdalo en dos variables y cambia el título a través de la segunda. Imprime el título a través de la primera. Explica con palabras por qué funciona así.

Test

Ponte a prueba

1. ¿Cuál es la diferencia entre una clase y un objeto?
2. Product sale = coffee; sale.Price = 8; ¿Qué pasa con el precio del café?
3. ¿Qué hay en el array justo después de Product[] cart = new Product[3];?
4. Un método recibe un producto como parámetro y cambia su precio. ¿Se ve el cambio después de la llamada?
5. Product gift = null; ¿Qué pasa en gift.Name?

Creado por Ivo Gergov como parte de la campaña de Evo Tech por una educación accesible en programación ·