0% encontró este documento útil (0 votos)
75 vistas13 páginas

Constructores y Destructores

Este documento describe las clases en .NET y sus características principales como tipos por referencia, herencia, encapsulación, polimorfismo y la clase base Object. También cubre cómo definir una clase, sus miembros y cómo instanciar objetos de una clase.

Cargado por

Fernando Santos
Derechos de autor
© Attribution Non-Commercial (BY-NC)
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
75 vistas13 páginas

Constructores y Destructores

Este documento describe las clases en .NET y sus características principales como tipos por referencia, herencia, encapsulación, polimorfismo y la clase base Object. También cubre cómo definir una clase, sus miembros y cómo instanciar objetos de una clase.

Cargado por

Fernando Santos
Derechos de autor
© Attribution Non-Commercial (BY-NC)
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

Clases: Tipos por referencia definidos por el usuario

Los tipos de datos se dividen en dos grupos: tipos por valor y tipos por referencia. Los tipos por referencia
realmente son clases, de las cuales debemos crear una instancia para poder usarlas, esa instancia o copia, se
crea siempre en la memoria lejana (heap) y las variables lo único que contienen es una referencia a la
dirección de memoria en la que el CLR (Common Language Runtime, motor en tiempo de ejecución de
.NET), ha almacenado el objeto recién creado.

En .NET Framework todo es de una forma u otra una clase, por tanto C# también depende de la creación de
clases para su funcionamiento, ya que todo el código que escribamos debemos hacerlo dentro de una clase.

Las clases: el corazón de .NET Framework

Todo lo que podemos hacer en .NET lo hacemos mediante clases. La librería de clases de .NET Framework es
precisamente el corazón del propio .NET, en esa librería de clases está todo lo que podemos hacer dentro de
este marco de programación; para prácticamente cualquier tarea que queramos realizar existen clases, y si
no existen, las podemos definir nosotros mismos, bien ampliando la funcionalidad de alguna clase existente
mediante la herencia, bien implementando algún tipo de funcionalidad previamente definida o simplemente
creándolas desde cero.

La herencia: Característica principal de la Programación Orientada a Objetos

El concepto de Programación Orientada a Objetos (POO) es algo intrínseco al propio .NET Framework, por
tanto es una característica que todos los lenguajes basados en este "marco de trabajo" tienen de forma
predeterminada, entre ellos el C#. De las características principales de la POO tenemos que destacar la
herencia, que en breve podemos definir como una característica que nos permite ampliar la funcionalidad
de una clase existente sin perder la que ya tuviera previamente. Gracias a la herencia, podemos crear una
nueva clase que se derive de otra, esta nueva clase puede cambiar el comportamiento de la clase base y/o
ampliarlo, de esta forma podemos adaptar la clase, llamémosla, original para adaptarla a nuestras
necesidades.

El tipo de herencia que .NET soporta es la herencia simple, es decir, solo podemos usar una clase como base
de la nueva, podemos agregar múltiple funcionalidad a nuestra nueva clase. Esta funcionalidad nos servirá
para aprovechar la que ya tienen muchas de las clases existentes en .NET, funcionalidad que solamente
podremos aplicar si previamente hemos firmado un contrato que asegure a la clase de .NET que la nuestra
está preparada para soportar esa funcionalidad.

Encapsulación y Polimorfismo

La encapsulación y el polimorfismo son otras dos características de la programación orientada a objetos.

La encapsulación nos permite abstraer la forma que tiene de actuar una clase sobre los datos que contiene o
manipula, para poder lograrlo se exponen como parte de la clase los métodos y propiedades necesarios para
que podamos manejar esos datos sin tener que preocuparnos cómo se realiza dicha manipulación.

El polimorfismo es una característica que nos permite realizar ciertas acciones o acceder a la información de
los datos contenidos en una clase de forma semi-anónima, al menos en el sentido de que no tenemos
porqué saber sobre que tipo de objeto realizamos la acción, ya que lo único que nos debe preocupar es que
podemos hacerlo, por la sencilla razón de que estamos usando ciertos mecanismos que siguen unas normas
que están adoptadas por la clase.

1
Object: La clase base de todas las clases de .NET

Todas las clases de .NET se derivan de la clase Object, es decir, lo indiquemos o no, cualquier clase que
definamos tendrá el comportamiento heredado de esa clase. El uso de la clase Object como base del resto
de las clases de .NET es la única excepción a la herencia simple soportada por .NET, ya que de forma
implícita, todas las clases de .NET se derivan de la clase Object independientemente de que estén derivadas
de cualquier otra.
Esta característica nos asegura que siempre podremos usar un objeto del tipo Object para acceder a
cualquier clase de .NET.

De los miembros que tiene la clase Object debemos resaltar el método ToString. Este método está pensado
para devolver una representación en formato cadena de un objeto. El valor que obtengamos al usar este
método dependerá de cómo esté definido en cada clase y por defecto lo que devuelve es el nombre
completo de la clase, si bien en la mayoría de los casos el valor que obtendremos al usar este método
debería ser más intuitivo, por ejemplo los tipos de datos primitivos tienen definido este método para que
devuelva el valor que contienen, de igual forma, nuestras clases también deberían devolver un valor
adecuado al contenido almacenado.

Nota:
Todos los tipos de datos de .NET, ya sean por valor o por referencia siempre están derivados de la
clase Object, por tanto podremos llamar a cualquiera de los métodos que están definidos en esa clase.

2
Definir una clase

En Visual C#, todo el código que queramos escribir, lo tendremos que hacer en un fichero con la extensión
.cs, dentro de ese fichero es donde escribiremos nuestro código que siempre estará incluido dentro de una
clase, aunque un fichero de código de C# puede contener una o más clases, es decir, no está limitado a una
clase por fichero.

En C# las clases se definen usando la palabra clave class seguida del nombre de la clase, el cuerpo de la clase
estará encerrada entre un par de llaves, que por otra parte es la forma habitual de definir bloques de código
en C#.
En el siguiente ejemplo definimos una clase llamada Cliente que tiene dos campos públicos.

class Cliente
{
public string sNombre;
public string sApellidos;
}

Una vez definida la clase podemos agregar los elementos (o miembros) que creamos conveniente.
En el ejemplo anterior, para simplificar, hemos agregado dos campos públicos, aunque también podríamos
haber definido cualquiera de los miembros permitidos en las clases.

Los miembros de una clase

Una clase puede contener cualquiera de estos elementos (miembros):

Enumeraciones
Campos
Métodos (funciones o procedimientos)
Propiedades
Eventos

Enumeraciones: Podemos usarlas para definir valores constantes relacionados, por ejemplo para indicar los
valores posibles de cualquier "característica" de la clase.

Campos: Variables usadas para mantener los datos que la clase manipulará.

Métodos: Acciones que la clase puede realizar, normalmente esas acciones serán sobre los datos que
contiene. Los métodos pueden devolver valores como resultado de la "acción" realizada o también pueden
devolver un valor void, que significa que realmente no devuelve nada.

Propiedades: "Características" de las clases y la forma de acceder "públicamente" a los datos que contiene.
Por ejemplo, podemos considerar que el nombre y los apellidos de un cliente son dos características del
cliente.

Eventos: Mensajes que la clase puede enviar para informar que algo está ocurriendo en la clase.

3
Características de los métodos y propiedades

Accesibilidad, ámbito y miembros compartidos

Accesibilidad y ámbito son dos conceptos que están estrechamente relacionados. Aunque en la práctica
tienen el mismo significado, ya que lo que representan es la "cobertura" o alcance que tienen los miembros
de las clases e incluso de las mismas clases que definamos.

Si bien cada uno de ellos tienen su propia "semántica", tal como podemos ver a continuación:

Ámbito

Es el alcance que la definición de un miembro o tipo puede tener. Es decir, cómo podemos acceder a ese
elemento y desde dónde podemos accederlo.
El ámbito de un elemento de código está restringido por el "sitio" en el que lo hemos declarado. Estos sitios
pueden ser:

Ámbito de bloque: Disponible únicamente en el bloque de código en el que se ha


declarado.
Ámbito de procedimiento: Disponible únicamente dentro del procedimiento, (función o
propiedad), en el que se ha declarado.
Ámbito de módulo: Disponible en todo el código de la clase o la estructura donde se ha
declarado.
Ámbito de espacio de nombres: Disponible en todo el código del espacio de nombres.

Accesibilidad

A los distintos elementos de nuestro código (ya sean clases o miembros de las clases) podemos darle
diferentes tipos de accesibilidad. Estos tipos de "acceso" dependerán del ámbito que queramos que tengan,
es decir, desde dónde podremos accederlos.
Los modificadores de accesibilidad son:

public: Acceso no restringido.


protected: Acceso limitado a la clase contenedora o a los tipos derivados de esta clase.
internal: Acceso limitado al proyecto actual.
protected internal: Acceso limitado al proyecto actual o a los tipos derivados de la clase
contenedora.
private: Acceso limitado al tipo contenedor.

Por ejemplo, podemos declarar miembros privados a una clase, en ese caso, dichos miembros solamente los
podremos acceder desde la propia clase, pero no desde fuera de ella.

Nota:
En C# cuando declaramos una variable sin indicar el modificador de accesibilidad, el ámbito será
privado.

4
Instanciar: Crear un objeto en la memoria

Una vez que tenemos una clase definida, lo único de lo que disponemos es de una especie de plantilla o
molde a partir del cual podemos crear objetos en memoria.

Para crear esos objetos en C# lo podemos hacer de dos formas, pero como veremos siempre será mediante
la instrucción new que es la encargada de crear el objeto en la memoria y asignar la dirección del mismo a la
variable usada en la parte izquierda de la asignación.

Declarar primero la variable y después instanciarla

Lo primero que tenemos que hacer es declarar una variable del tipo que queremos instanciar, esto lo
hacemos de la misma forma que con cualquier otro tipo de datos:

Cliente cli1;

Con esta línea de código lo que estamos indicando a C# es que tenemos intención de usar una variable
llamada cli1 para acceder a una clase de tipo Cliente. Esa variable, cuando llegue el momento de usarla,
sabrá todo lo que hay que saber sobre una clase Cliente, pero hasta que no tenga una "referencia" a un
objeto de ese tipo no podremos usarla.

La asignación de una referencia a un objeto Cliente la haremos usando la instrucción new seguida del
nombre de la clase:

cli1 = new Cliente();

A partir de este momento, la variable cli1 tiene acceso a un nuevo objeto del tipo Cliente, por tanto
podremos usarla para asignarle valores y usar cualquiera de los miembros que ese tipo de datos contenga:

cli1.sNombre = "Antonio";
cli1.sApellidos = "Ruiz Rodríguez";

Cliente cli1;
cli1 = new Cliente();
cli1.sNombre = "Antonio";
cli1.sApellidos = "Ruiz Rodríguez";
Console.WriteLine(cli1.sNombre + " " + cli1.sApellidos);
/*Muestra en pantalla “Antonio Ruiz Rodríguez” variable cli1*/

5
Declarar e instanciar en un solo paso

La otra forma de instanciar una clase es haciéndolo al mismo tiempo que la declaramos. En C# esto se hace
como si uniéramos la declaración y la instanciación en una sola instrucción:

Cliente cli2 = new Cliente();

A partir de este momento, la variable cli2 tiene acceso a un nuevo objeto del tipo Cliente, por tanto
podremos usarla para asignarle valores y usar cualquiera de los miembros que ese tipo de datos contenga:

cli2.sNombre = "Antonio";
cli2.sApellidos = "Ruiz Rodríguez";

Cliente cli2 = new Cliente();


cli2.sNombre = "Antonio";
cli2.sApellidos = "Ruiz Rodríguez";
Console.WriteLine(cli2.sNombre + " " + cli2.sApellidos);
/*Muestra en pantalla “Antonio Ruiz Rodríguez” variable cli2*/

De esta forma se asignará a la variable cli2 una referencia a un nuevo objeto creado en la memoria, el cual
será totalmente independiente del resto de objetos creados con esa misma clase.

El constructor: El punto de inicio de una clase

Cada vez que creamos un nuevo objeto en memoria estamos llamando al constructor de la clase. En C# el
constructor es una especie de método que se llama de la misma forma que la clase.

En el constructor de una clase podemos incluir el código que creamos conveniente, pero realmente
solamente deberíamos incluir el que realice algún tipo de inicialización, en caso de que no necesitemos
realizar ningún tipo de inicialización, no es necesario definir el constructor, ya que el propio compilador lo
hará por nosotros. Esto es así porque todas las clases deben implementar un constructor, por tanto si
nosotros no lo definimos, lo hará el compilador de C#.

6
Constructores parametrizados

De la misma forma que podemos tener métodos sobrecargados, también podemos tener constructores
sobrecargados, ya que en C# el constructor es como una función con un tratamiento especial que devuelve
un nuevo objeto.

La ventaja de tener constructores que admitan parámetros es que podemos crear nuevos objetos indicando
algún parámetro, por ejemplo un fichero a abrir o, en el caso de la clase Cliente, podemos indicar el nombre
y apellidos del cliente o cualquier otro dato que creamos conveniente.

Para comprobarlo, podemos ampliar la clase definida anteriormente para que también acepte la creación de
nuevos objetos indicando el nombre, los apellidos y edad del cliente.

Teniendo esta declaración de la clase Cliente, podemos crear nuevos clientes de dos formas:

Cliente cli1;
cli1 = new Cliente();
cli1.sNombre = "Antonio";
cli1.sApellidos = "Ruiz Rodríguez";
Console.WriteLine(cli1.sNombre + " " + cli1.sApellidos);
/*Muestra en pantalla “Antonio Ruiz Rodríguez” variable cli1*/

Cliente cli2 = new Cliente();


cli2.sNombre = "Antonio";
cli2.sApellidos = "Ruiz Rodríguez";
Console.WriteLine(cli2.sNombre + " " + cli2.sApellidos);
/*Muestra en pantalla “Antonio Ruiz Rodríguez” variable cli2*/

Cliente cli3;
cli3 = new Cliente("Jose", "Sánchez", 22);
Console.WriteLine(cli3.sNombre + " " + cli3.sApellidos + " " +
cli3.nEdad);
/*Muestra en pantalla "Jose Sánchez 22" de la variable cli3*/

class Cliente
{
public string sNombre;
public string sApellidos;
public int nEdad;

public Cliente()
{
//Constructor vacio para aquellos que no tienen
sobrecargas
// ej: cli1 y cli2
}
public Cliente (string elNombre, string losApellidos, int
laEdad) : this()
{
//Constructor con sobrecargas ej: cli3
sNombre = elNombre;
sApellidos = losApellidos;
nEdad = laEdad;
}
}
7
Como podemos comprobar, en ciertos casos es más intuitiva la segunda forma de crear objetos del tipo
Cliente, además de que así nos ahorramos de tener que asignar individualmente los campos Nombre,
Apellidos y Edad.

Esta declaración de la clase Cliente la podríamos haber hecho de una forma diferente. Por un lado tenemos
un constructor "normal" (no recibe parámetros). En ese segundo constructor asignamos la edad, ya que, se
instancie como se instancie la clase, nos interesa saber siempre la edad.

La instrucción this se emplea para acceder a la instancia actual, es decir al objeto que está en la memoria, y
cuando lo usamos de la forma mostrada en el código, realmente llama al constructor, en este caso sin
parámetros, aunque de haberlo necesitado podemos indicarle los argumentos que creamos conveniente,
siempre que exista un constructor con ese número de parámetros.
La llamada a otros constructores de la misma instancia, solo podemos hacerla desde un constructor y esa
llamada debe estar antes del inicio del código de la clase, es decir, antes de la llave de apertura.

Cuando C# no crea un constructor automáticamente

Si nosotros no definimos un constructor, lo hará el propio compilador de C#, y cuando lo hace


automáticamente, siempre es un constructor sin parámetros.

Pero hay ocasiones en las que nos puede interesar que no exista un constructor sin parámetros, por
ejemplo, podemos crear una clase Cliente que solo se pueda instanciar si le pasamos, por ejemplo el
número de identificación fiscal, (NIF), en caso de que no se indique ese dato, no podremos crear un nuevo
objeto Cliente; de esta forma nos aseguramos de que el NIF siempre esté especificado. Seguramente por ese
motivo, si nosotros definimos un constructor con parámetros, C# no lo crea automáticamente sin
parámetros. Por tanto, si definimos un constructor con parámetros en una clase y queremos que también
tenga uno sin parámetros, lo tenemos que definir nosotros mismos, aunque no es necesario que el
constructor sin parámetros ejecute código, puede estar declarado sin más.

El destructor: El punto final de la vida de una clase

De la misma forma que una clase tiene su punto de entrada o momento de nacimiento en el constructor,
también tienen un sitio que se ejecutará cuando el objeto creado en la memoria ya no sea necesario, es
decir, cuando acabe la vida del objeto creado.

El destructor de C# se llama igual que la clase pero precedida del carácter ~ y no puede tener ningún
modificador de visibilidad. Y solo es necesario definirlo si nuestra clase utiliza algún tipo de recurso, por
tanto no es necesario definirlo si no tenemos que liberar expresamente algún recurso asignado en el
constructor.

La definición del destructor de nuestra clase Cliente podía ser algo como esto:

~Cliente()
{

8
El que un destructor no sea accesible externamente es por la sencilla razón de que es el propio CLR
(Common Language Runtime, motor en tiempo de ejecución de .NET), el que se encarga de gestionar la
destrucción de los objetos que ya no son utilizados. Debido a que no es posible invocar al destructor desde
el objeto creado en la memoria, debemos implementar explícitamente un método que sea el que se
encargue de hacer esa limpieza de los recursos utilizados por nuestra clase, ese método suele tener el
nombre Close o Dispose, en este último caso, lo que se recomienda es que nuestra clase implemente la
interfaz IDisposable con idea de que si no se llama expresamente al método que libera la memoria, sea el
propio runtime del .NET Framework el que lo llame cuando el objeto ya no sea necesario mantenerlo en
memoria.

Es importante saber que los destructores no se llaman de forma inmediata, es decir, es posible que un
objeto ya no se esté usando, pero el CLR (Common Language Runtim) no llamará al destructor hasta que no
lo crea conveniente, por tanto si nuestra clase utiliza recursos externos es imperativo que el usuario que
utilice nuestra clase llame de forma explícita al método que hayamos definido para liberar esos recursos.

9
Código 1 final:

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

namespace Constructores_y_destructores
{
class Program
{
static void Main(string[] args)
{
Cliente cli1;
cli1 = new Cliente();
cli1.sNombre = "Antonio";
cli1.sApellidos = "Ruiz Rodríguez";
Console.WriteLine(cli1.sNombre + " " + cli1.sApellidos);
/*Muestra en pantalla Antonio Ruiz Rodríguez variable cli1*/

Cliente cli2 = new Cliente();


cli2.sNombre = "Antonio";
cli2.sApellidos = "Ruiz Rodríguez";
Console.WriteLine(cli2.sNombre + " " + cli2.sApellidos);
/*Muestra en pantalla Antonio Ruiz Rodríguez variable cli2*/

Cliente cli3;
cli3 = new Cliente("Jose", "Sánchez", 22);
Console.WriteLine(cli3.sNombre + " " + cli3.sApellidos + " " + cli3.nEdad);
/*Muestra en pantalla "Jose Sánchez 22" de la variable cli3*/

Console.ReadKey();
}
}
class Cliente
{
public string sNombre;
public string sApellidos;

10
public int nEdad;

public Cliente()
{
//Constructor vacio para aquellos que no tienen sobrecargas
//ej: cli1 y cli2
}

public Cliente(string elNombre, string losApellidos, int laEdad)


: this()
{
//Constructor con sobrecargas ej: cli3
sNombre = elNombre;
sApellidos = losApellidos;
nEdad = laEdad;
}

~Cliente()
{
//Destructor de nuestra clase Cliente
}
}

11
Como se muestra en el siguiente código se heredan de la clase Persona los parámetros hacia la clase
Alumnos.

class Persona
{
public string sNombre;
public string sApellidos;
public int nEdad;
public char cSexo;
~Persona()
{
}
}
class Alumnos : Persona
{
public char nGrupo;
public int nSemestre;
~Alumnos()
{
}
}

Si declaramos una variable de tipo Persona tendrá únicamente los parámetros de:

public string sNombre;


public string sApellidos;
public int nEdad;
public char cSexo;

Al momento de crear una clase de tipo Alumnos tendrá como parámetros:

public char nGrupo;


public int nSemestre;

Para poder heredar lo de la clase Persona hacia la clase Alumnos debemos poner el carácter : para que así la
clase Alumnos ahora también tenga acceso a los parámetros de la clase Persona (Clase padre).
La clase Alumnos ahora tendrá los siguientes parámetros heredados de la clase Persona.

public string sNombre;


public string sApellidos;
public int nEdad;
public char cSexo;
public char nGrupo;
public int nSemestre;

12
Código 2 final:

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

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Alumnos Alumno = new Alumnos();
Alumno.sNombre = "Juan";
Alumno.sApellidos = "Rodriguez";
Alumno.nEdad = 25 ;
Alumno.cSexo = 'M';
Alumno.nGrupo = 'A';
Alumno.nSemestre = 3;
Console.WriteLine("El nombre es: " + Alumno.sNombre);
Console.WriteLine("Los apellidos son: " + Alumno.sApellidos);
Console.WriteLine("La edad es: " + Alumno.nEdad);
Console.WriteLine("El sexo es: " + Alumno.cSexo);
Console.WriteLine("El grupo es: " + Alumno.nGrupo);
Console.WriteLine("El semestre es: " + Alumno.nSemestre);
Console.ReadKey();
}
}
class Persona
{
public string sNombre;
public string sApellidos;
public int nEdad;
public char cSexo;
~Persona()
{
}
}
class Alumnos : Persona
{
public char nGrupo;
public int nSemestre;
~Alumnos()
{
}
}
}

13

También podría gustarte