Portal » CSharp » Herencia en C#

Herencia en C#

Aprenderemos como implementar la herencia en C#,con este ejemplo pretendo que quede mas claro el concepto aplicado a c#. lo que haremos sera un proyecto para calcular el area de las ya conocidas figuras geometricas:circulo,cuadrado,rectangulo y triangulo.

Un poco de teoria(muy breve)

Como ya sabemos la herencia nos permite tomar partes de una clase padre y poder usarla en lo que llamamos subclases,eso permite ahorrarnostener que escribir nuevamente el mismo codigo en varias clases…ahora pensemos un momento,en el caso de una figura geometrica como puedo aplicar la herencia?  :o Facil! si recordamos un poco como calcular  areas(sino hay que ir de nuevo a secundaria).

circulo=pi*r^2
cuadrado=L^2
rectangulo=b*h
triangulo=(b*h)/2

Ahora que tienen en comun, bueno podriamos partir del hecho que todas las figuras geometricas tienen al menos un lado(sea radio,base,altura..),entonces podriamos crear una clase llamada Figura que tenga como atributo Lado e ir haciendo la especialización de cada subclase derivada,agregandole la informacion que sea necesaria, de igual manera podriamos tener un metodo llamado areaen la clase principal  y para cada figura irlo adecuando(lo que se llamaria sobreescritura de metodo o override en POO) lo mismo que su perimetro.

Manos a la obra
para verlo de forma mas grafico en un diagrama de clases,nuestra implementacion sera algo como esto

Ya teniendo el panorama bien explicado,al menos lo intente, abramos visual studio y creamos un nuevo proyecto de formulario en c#, le pondremos de nombre Tarea3Figuras(era una tarea  ;D), y de momento realizaremos  la interfaz grafica,nos debera quedar como la siguiente figura

Ademas cambiamos en la propiedad name de cada control ,tal como aparece en la figura.

En el control toolstrip agregamos cuatro imagenes,las adjuntare al final del post para cada figura geometrica,la idea es que al hacer click solo muestre lo necesario,en el caso del circulo un solo lado,para el triangulo dos,y para el triangulo tres(por el perimetro)

Creando las clases

Desde el explorador de soluciones necesitamos crear las clases para cada figura geometrica ademas de la clase padre,la llamaremos Figura. Sobre el proyecto damos clic derecho y en el menu contextual seleccionamos agregar>Nuevo elemento y seleccionamos clase, debera aparecernos lla nueva clase en el explorador de soluciones, luego agregamos las otras 4 clases: Triangulo,Cuadrado,Rectangulo y Circulo. nos quedara como la siguiente imagen

Editando las clases

comenzaremos a escribir codio en la clase padre, Figura, para luego ir haciendo la especialziacion en cada clase. en el explorador de soluciones damos doble clic Sobre Figura.cs   y agregaremos este codigo.

using System;
using System.Collections.Generic;
using System.Text;

namespace Tarea3Figuras
{
   abstract class Figura
    {
        private int lado1;
        public int Lado1 {
            set {
                if (value < 0) {
                    lado1 = 0;
                }
                else
                {
                    lado1 = value;
                }
            }
            get{
            return lado1;
            }
        }
       public abstract float area();
       public abstract float perimetro();
    }

}

Explicacion del codigo
si observan hemos declarado al clase como abstract la explicacion es es que cuando no queremos instanciar objetos de una clase es decir usar algo como clase nombre=new clase(parametros..) lo que hacemos es anteponer la sentencia abtsract al nombre de la clase, para nuestro caso como la clase Figura solo nos servira como un molde para las clases derivadas entonces anteponemos abstract al nombre de la clase.

el siguiente bloque de codigo

      public int Lado1 {
            set {
                if (value < 0) {
                    lado1 = 0;
                }
                else
                {
                    lado1 = value;
                }
            }
            get{
            return lado1;
            }
        }

sirve para declarar los atributos de clase con sus respectivos metodos modificadores y de acceso, get y set observen que el atributo lado1 esta como private debido a que no queremos acceder a el desde fuera de la clase Figura.

las ultimas dos lineas

       public abstract float area();
       public abstract float perimetro();

Son los dos metodos que nos serviran como base para calcular el area y perimetro de cada figura dependiendo la cantidad de lados que tenga. al igual que la clase estan declarados como abstract en su modificador de acceso, para evitar asignarlos a instancias .

Bien con eso ya tenemos nuestro modelo basico,como pudieron ver solo delclaramos un solo lado, ya que como minimo las figuras tienen un lado,en el caso del circulo, luego iremos haciendo la especializacion para cada clase.

La clase Circulo
Siguiendo con nuestro ejemplo ahora vamos a trabajar sobre la clase Circulo, de manera que podamos asignarle sus atributos y metodos partiendo de la clase Figura. Damso doble clic sobre Circulo.cs, agregamos el siguiente codigo.

using System;
using System.Collections.Generic;
using System.Text;

namespace Tarea3Figuras
{
    class Circulo:Figura
    {
       public Circulo(int radio) {
            Lado1 = radio;
        }
        public override float area()
        {
            return 3.141516F * Lado1 * Lado1;
        }
        public override float perimetro()
        {
            return 3.141516F * 2 * Lado1;
        }
    }
}

Explicacion

o primero que notamos es que estamos aplicando la herencia de la clase Figura. class Circulo:Figura esta notacion indica que la clase circulo Hereda los atributos de la clase Figura si programas en java es lo mismo que usar la sentencia extend, como hemos heredado todos lso atributos y metodos,ya no es necesario volver a delclararlos, lo siguiente que tenemos es el constructor

       public Circulo(int radio) {
            Lado1 = radio;
        }

el cual se caracteriza por tener el mismo nombre de la clase y ademas ser publico. el constructor se utiliza para iniciarlizar los objetos cada vez que creamos un objeto derivado de Circulo, aqui estamos diciendo que el objeto circulo recibira un parametro radio y debera ser asignado al atributo Lado1, como el circulo solo tiene un lado, ya no hacemos nada mas,lo siguiente es trabajar sobre los metodos y aqui aplicamos otro concepto de POO llamados sobreescritura de metodos, el cual nos sirve para usar un metodo para varias cosas

        public override float area()
        {
            return 3.141516F * Lado1 * Lado1;
        }
        public override float perimetro()
        {
            return 3.141516F * 2 * Lado1;
        }

en lugar de llamar al metodo por ejemplo areacirculo y perimetroCirculo usamos los mismos nombres que utilizamos en las clase Figura, con la salvedad de que agregamos la sentencia override para indicar que vamos a cambiar el comportamiento del metodo,como sabemos que calcular el area de un circulo es diferente a la de un cuadrado,cada vez que se llame a este metodo retornaremos el cuadrado del lado multiplicado por pi, y en el caso del perimetro 2*pi*lado

La clase Rectangulo
bien si ya comprendiste de que va la herencia, aqui veamos algo un tanto diferente,que pasa si nuestra figura tuviese 4 lados y no 1 como en el rectangulo?, pues deberíamos agregar otro atributo mas  aparte del que ya teniamos.

using System;
using System.Collections.Generic;
using System.Text;

namespace Tarea3Figuras
{
class Rectangulo:Figura
{
private int lado2;

public int Lado2 {
set {
if (value < 0)
{
lado2 = 0;
}
else {
lado2 = value;
}
}
get {
return lado2;
}
}
public Rectangulo(int lado1, int lado2) {
this.Lado1 = lado1;
this.Lado2 = lado2;
}
public override float area()
{
return Lado1 * Lado2;
}
public override float perimetro()
{
return (2 * Lado1) + (2 * Lado2);
}
}
}

observen como nuevamente estamos aplicando la herencia Rectangulo:Figura sabemos que ya no es necesario declarar lado1 por que lo heredo de la clase figuras,pero como necesitamos otro lado mas(base y altura) agregamos la declaracion de ese lado en la clase

private int lado2;
public int Lado2 {
set {
if (value < 0)
{
lado2 = 0;
}
else {
lado2 = value;
}
}
get {
return lado2;
}
}

si ven nuevamente declaramos otro atributo llamado lado2 para ser consistentes con acceso privado y sus respectivos metodos get y set para modificar o consultar el estado de ese atributo,asi cada vez que creemos un objeto derivado de la clase rectangulo tendra dos lados,
por consiguiente tambien modifcamos su construtor de la siguiente forma

public Rectangulo(int lado1, int lado2) {
this.Lado1 = lado1;
this.Lado2 = lado2;
}

aqui ya estamos asignando los dos valores que pasemos como argumentos en la creacion de la instancia y estos se guardaran respectivamente en lado1 y lado2.

nuevamente haremos una sobreescritura de metodos,para poder calcular el area y perimetro del rectangulo,aqui ya no usara la del circulo sino su propia version de los metodos.

public override float area()
{
return Lado1 * Lado2;
}
public override float perimetro()
{
return (2 * Lado1) + (2 * Lado2);
}

Bien como creo que ya se entendio el concepto de las dos siguientes solo dejare el codigo,la explicacion es la misma que las dos figuras anteriores, hay que  sobreescribir los metodos,para que dependiendo que figura sea utilizada use su propia version del metodo de area y perimetro y de ser  necesario se agregan mas lados

using System;
using System.Collections.Generic;
using System.Text;

namespace Tarea3Figuras
{
    class Cuadrado:Figura
    {
        public Cuadrado(int lado1) {
            this.Lado1 = lado1;
        }
        public override float area()
        {
            return Lado1 * Lado1;
        }
        public override float perimetro()
        {
            return 4 * Lado1;
        }
    }
}

Observar que solo se necesito un lado,ya que en el caso del circulo todos los 4 lados son iguales,no tendria sentido declarar 3 lados mas,el constructor por lo tanto solo asignara un lado a las instancias que se creen.

la clase Triangulo

using System;
using System.Collections.Generic;
using System.Text;

namespace Tarea3Figuras
{
    class Triangulo:Figura
    {
        private int lado2;
        private int lado3;

        public int Lado2 {
        
            set {
                if (value < 0) {
                    lado2 = 0;
                }
                else{
                lado2=value;
                }
            }
            get {
                return lado2;
            }
        }

        public int Lado3 {
            set {
                if (value < 0)
                {
                    lado3 = 0;
                }
                else {
                    lado3 = value;
                }
            }
            get {
                return lado3;
            }
        }
        public Triangulo(int tbase, int altura) {
            Lado1 = tbase;
            Lado2 = altura;
        }
        public Triangulo(int L1, int L2, int L3) {
            Lado1 = L1;
            Lado2 = L2;
            Lado3 = L3;
        }
        public override float area()
        {
            return (Lado1 * Lado2) / 2.0F;
        }
        public override float perimetro()
        {
            return Lado1 + Lado2 + Lado3;
        }
    }
}

agregamos dos atributos mas Lado2,Lado3 ya que un triangulo puede ser equilatero,isoceles o escaleno(todos los lados distintos) por lo cual los tres lados podrian ser diferentes, agregamos su constructor con los tres lados y finalmente hacemos la sobreescritura de sus metodos para calcular el area y perimetro.

Agregando codigo  al formulario

Lo que sigue es mas bien como integrar todo en la aplicacion y agregar la funcionalidad a los botones,dependiendo que figura sea seleccionada asi deberan aparecer o no algunos campos,por ejemplo si seleccionamos un circulo,sabemos que solo se necesita que se muestre un lado,por otra parte para un triangulo necesitamos ingresar tres lados,ademas cada figura se le puede calcular su area o perimetro, por lo que tambien se debera ajustar el codigo.
Hacemos doble clic sobre el boton btnCalcular y dentro de  su evento click, escribiremos lo siguiente
try
{
switch (tipo_figura)
{
case 1:
if (rdbArea.Checked == true)
{
Triangulo tri = new Triangulo(int.Parse(txtLado1.Text), int.Parse(txtLado2.Text));
txtResultao.Text = Convert.ToString(tri.area());
}
else
{
Triangulo tri = new Triangulo(int.Parse(txtLado1.Text), int.Parse(txtLado2.Text), int.Parse(txtLado3.Text));
txtResultao.Text = Convert.ToString(tri.perimetro());
}
break;
case 2:
if (rdbArea.Checked == true)
{
Cuadrado cuadr = new Cuadrado(int.Parse(txtLado1.Text));
txtResultao.Text = Convert.ToString(cuadr.area());
}
else
{
Cuadrado cuadr = new Cuadrado(int.Parse(txtLado1.Text));
txtResultao.Text = Convert.ToString(cuadr.perimetro());
}
break;
case 3:
if (rdbArea.Checked == true)
{
Circulo circ = new Circulo(int.Parse(txtLado1.Text));
txtResultao.Text = Convert.ToString(circ.area());
}
else
{
Circulo circ = new Circulo(int.Parse(txtLado1.Text));
txtResultao.Text = Convert.ToString(circ.perimetro());
}
break;
case 4:
if (rdbArea.Checked == true)
{
Rectangulo rect = new Rectangulo(int.Parse(txtLado1.Text), int.Parse(txtLado2.Text));
txtResultao.Text = Convert.ToString(rect.area());
}
else
{
Rectangulo rect = new Rectangulo(int.Parse(txtLado1.Text), int.Parse(txtLado2.Text));
txtResultao.Text = Convert.ToString(rect.perimetro());
}
break;
}
}
//catch
catch (Exception) {
MessageBox.Show(“Error la ingresar datos”);
}

el codigo es extenso,pero repetitivo asi que no lo explicare todo  ::) estamos usando un case para que dependiendo que se seleccione en en radio button,asi aparezcan o desaparezcan algunos campos de texto en el caso de que se haya seleccionado el triangulo se podra elegir entre calcular el area o perimetro

case 1:
if (rdbArea.Checked == true)
{
Triangulo tri = new Triangulo(int.Parse(txtLado1.Text), int.Parse(txtLado2.Text));
txtResultao.Text = Convert.ToString(tri.area());
}
else
{
Triangulo tri = new Triangulo(int.Parse(txtLado1.Text), int.Parse(txtLado2.Text), int.Parse(txtLado3.Text));
txtResultao.Text = Convert.ToString(tri.perimetro());
}
break;

 

se creara un nuevo objeto del tipo Triangulo llamado tri y se le pasaran como argumentos los lados que se digiten en los tres texbox,luego se invocara al metodo dependiendo de la seccion de area o perimetro y el resultado sera mostrado como cadena en el textbox txtResultado., para las demas figuras es igual,solo cambia el tipo de objetos que se creara dependiendo de la seleccion.

creamos otro metodo para reiniciar los controles
private void reinicia_controles() {
foreach (Control ctr in this.groupBox2.Controls) {
ctr.Visible = false;
ctr.Text = “”;
}
txtResultao.Text = “”;
btnCalcular.Text = “Calcular”;
btnCalcular.Visible = true;
btnCalcular.Enabled = true;
}

otro mas para que muestre los campos correspondientes para el area y perimetro

private void selecciona_areafigura() {
switch (tipo_figura) {
case 1:
lblLado1.Text = “Base”;
lblLado2.Text = “Altura”;
lblLado1.Visible = true;
lblLado2.Visible = true;
txtLado1.Visible = true;
txtLado2.Visible = true;
break;
case 2:
lblLado1.Text = “Lado”;
lblLado1.Visible = true;
txtLado1.Visible = true;
break;
case 3:
lblLado1.Text = “Radio”;
lblLado1.Visible = true;
txtLado1.Visible = true;
break;
case 4:
lblLado1.Text = “Base”;
lblLado2.Text = “Altura”;
lblLado1.Visible = true;
txtLado1.Visible = true;
lblLado2.Visible = true;
txtLado2.Visible = true;
break;
}
}

private void selecciona_perimetroFigura() {
switch (tipo_figura) {
case 1:
lblLado1.Text = “Lado1”;
lblLado2.Text = “Lado2”;
lblLado3.Text = “Lado3”;
foreach (Control ctr in this.groupBox2.Controls)
{
ctr.Visible = true;
}
break;
case 2:
lblLado1.Text = “Lado”;
lblLado1.Visible = true;
txtLado1.Visible = true;
break;
case 3:
lblLado1.Text = “Radio”;
lblLado1.Visible = true;
txtLado1.Visible = true;
break;
case 4:
lblLado1.Text = “Base”;
lblLado2.Text = “Altura”;
lblLado1.Visible = true;
txtLado1.Visible = true;
lblLado2.Visible = true;
txtLado2.Visible = true;
break;
}
}

y en los toolstrip agregamos el codigo para cada figura

private void toolStripButton4_Click(object sender, EventArgs e)
{
//Triangulo
tipo_figura = 1;
groupBox2.Text = “Triangulo”;
rdbArea.Checked = true;
reinicia_controles();
selecciona_areafigura();
}

private void toolStripButton2_Click(object sender, EventArgs e)
{
//cuadrado
tipo_figura= 2;
groupBox2.Text = “Cuadrado”;
rdbArea.Checked = true;
reinicia_controles();
selecciona_areafigura();

}

private void toolStripButton1_Click(object sender, EventArgs e)
{
//Circulo
tipo_figura = 3;
groupBox2.Text = “Circulo”;
rdbArea.Checked = true;
reinicia_controles();
selecciona_areafigura();
}

private void toolStripButton3_Click(object sender, EventArgs e)
{
//Rectangulo
tipo_figura = 4;
groupBox2.Text = “Rectangulo”;
rdbArea.Checked = true;
reinicia_controles();
selecciona_areafigura();
}

y el codigo para cerrar la aplicacion en el btnCerrar

private void btnCerrar_Click(object sender, EventArgs e)
{
Application.Exit();
}

muy bien eso es todo, no me detuve en lo ultimo debido a que la intencion era explicar a herencia,lo demas es pura programación para dejarlo mas presentable, si quieren ver como queda todo unido pueden bajarse el codigo adjunto,deben tener vs 2012 para poder abrilo, igual si tienen dudas pueden hacerlas aqui.
Bajar adjunto

Acerca de franklinrony

apasionado del blogin, estudiante de ingenieria en informatica
  • fernando

    donde esta el codigo?

    • webmercadonegro

      gracias por escribir, el codigo esta dentro del propio articulo o a que te refieres?

  • fernando

    Al final del articulo mencionas: “pueden bajarse el codigo adjunto”.
    Este codigo de donde lo bajo? Lo que pasa es que me manda un error el codigo.

    Gracias.

  • Gabriel

    como lo hago en consola? sin los forms? Gracias

  • Keeeeev

    Disculpen esto tiene clases abstractas y arreglo de objetos no?
    Saludos cordiales

  • Veronica Orozco Mancinas

    Error 4 ‘WindowsFormsApplication9.Form1’ no contiene una definición de ‘groupBox2’ ni se encontró ningún método de extensión ‘groupBox2’ que acepte un primer argumento de tipo ‘WindowsFormsApplication9.Form1’ (¿falta una directiva de uso o una referencia de ensamblado?) C:Usersveronica orozcoDocumentsVisual Studio 2010ProjectsWindowsFormsApplication9WindowsFormsApplication9Form1.cs 105 30 WindowsFormsApplication9

    como quito eso