Está en la página 1de 35

Marco Besteiro y Miguel Rodrguez

Clases

Clases.
Introduccin
La Programacin Orientada a Objetos permite realizar grandes programas mediante la
unin de elementos ms simples, que pueden ser diseados y comprobados de manera
independiente del programa que va a usarlos. Muchos de estos elementos podrn ser
reutilizados en otros programas.
A estas piezas, mdulos o "componentes", que interactan entre s cuando se
ejecuta un programa, se les denomina objetos. Los objetos contienen datos y funciones
que actan sobre esos datos.
Durante la ejecucin de un programa, los objetos interactan entre s pasndose
mensajes y devolviendo respuestas a estos mensajes. Es fundamental darse cuenta de
que un objeto no necesita conocer el funcionamiento interno de los dems objetos para
poder interactuar con ellos (igual que el hombre no necesita conocer cmo 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 cmo va a recibir la
respuesta (al hombre le puede ser suficiente para utilizar el coche saber cmo conducir
acelerar, utilizar el volante, etc...-, cmo 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 anlogos 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 definicin genrica de estos objetos
anlogos se realiza mediante la clase. As, una clase contiene una completa y detallada
descripcin de la informacin 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 tambin 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
encapsulacin, ocultamiento o abstraccin de datos. De ordinario una clase ofrece un
conjunto de mtodos pblicos a travs de los cuales se puede actuar sobre los datos, que
sern privados. Estas funciones o mtodos pblicos 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 informacin. Esto sera imposible si se accediera libre e
independientemente a cada variable miembro. Al usuario le es suficiente con saber
1/35

Marco Besteiro y Miguel Rodrguez

Clases

cmo 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 ms 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 caractersticas 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 mtodos que son funciones que operan sobre esos datos. El conjunto
de campos y mtodos de una clase constituyen sus miembros.
El siguiente es un ejemplo de definicin y declaracin de una clase:
public class Rectangulo
{
//variables miembro, datos o atributos
int x;
int y;
private double ancho;
private double largo;
//funciones miembro o mtodos
public Rectngulo (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
definicin de un tipo de dato, realizada por el programador o proporcionada por el
sistema. Es una abstraccin lgica. Sin embargo, el objeto es un ejemplar de una clase,
que tiene una existencia fsica ya que est fsicamente 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 Rodrguez

Clases

int unaVariable = 7;

En esta sentencia, el programador distingue perfectamente entre el tipo de dato que es


un entero, concepto o abstraccin lgica- y la variable de ese tipo, que es un ejemplar
de un entero, con una realidad fsica, 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,
Rectngulo 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 Rectngulo. Despus de este paso,
unRect no apunta a nada, no referencia ningn objeto.
b ) Crear un objeto de la clase y asignarlo a la referencia anterior.
unRect = new Rectngulo(5,7);

En la sentencia anterior, el operador new seguido de un constructor de la clase crea


un objeto de la clase Rectngulo es decir, reserva el espacio de memoria que sea
necesario para un objeto de esa clase- y devuelve una referencia al objeto creado. El
smbolo = asigna el objeto recin creado a la referencia unRect. El objeto se
almacena en el heap o montn 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 asignacin 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 montn.

Montn
Pila

unRect
Referencias a objetos de la
clase Rectngulo
doRect

3/35

ancho

5.0

largo

7.0

ancho

23.0

largo

347.0

Objetos

Marco Besteiro y Miguel Rodrguez

Clases

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

En la expresin anterior se crea una referencia unRect de tipo Rectngulo y se le


asigna un objeto creado con el operador new. new crea el objeto fsico, que es
almacenado en memoria, el objeto, y unRect es una referencia a un objeto de tipo
Rectngulo. 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 ningn tipo de confusin 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 (mtodos, propiedades,
indexadores, eventos, operadores, constructores y destructores como CacularArea() y
Rectngulo()) 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 declaracin de clase consiste en un conjunto opcional de atributos se estudiarn
ms adelante- seguidos por un conjunto tambin 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++. Despus 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# slo se permite herencia simple, es decir, slo puede heredarse desde una clase.
Sin embargo, como en Java, se puede implementar ms de una interface.

4/35

Marco Besteiro y Miguel Rodrguez

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 explicacin detallada de los modificadores, ms
adelante, en este mismo captulo.
Aunque se volver a recalcar al hablar de los tipos de acceso, en este libro se seguirn la
recomendaciones de Microsoft respecto a cmo escribir los nombres de los miembros
de una clase.

Se escriben con minsculas los nombres de parmetros y campos privados o


protegidos de una clase. Por ejemplo:
private int unEntero;
protected string cadena;

Los miembros pblicos, las clases, etc, se escriben con maysculas. Por
ejemplo:
class MiClase{}
namespace MiNamespace;

Las constantes con maysculas. Por ejemplo:


public const double PI = 3.14;

Los nombre de una sla letra con minsculas:


int x=8;
private string s;

Los miembros de una clase pueden ser:

Constructores
Destructores
Constantes
Campos
Mtodos
Propiedades
Indexadores
Operadores

A continuacin, se estudian cada uno de ellos.

Constantes y miembros de slo 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 Rodrguez

Clases

Por ejemplo:
class Matemticas
{
public const double PI=3.141592;
}

Una constante es un valor que no puede ser cambiado y no se le puede asignar ningn
valor. Por eso es imprescindible inicializarla en la propia clase. Esto significa que no
podra haberse incluido en la clase anterior una lnea como la siguiente:
public

const double E;

Un campo de slo lectura readonly- es muy parecido a una constante pero


proporciona un poco ms de flexibilidad que una constante, ya que permite inicializarlo
despus por ejemplo- de algn clculo. 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 informacin del objeto de la clase que se ha creado.
Son aqullas caractersticas 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 travs de mtodos 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 almacenarn una copia de las variables de tipo valor y en
el segundo, una referencia a los objetos. Tambin 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 contraposicin a las variables estticas 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 estn separados incluso fsicamente- de los datos de otro objeto.
Por esta razn, los cambios que se realicen en los campos de un objeto no afectan para
nada a los campos de los dems 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 fsicamente. Por ejemplo:
using System;

6/35

Marco Besteiro y Miguel Rodrguez

Clases

public class Rectangulo


{
//variables miembro, datos o atributos
int x;
int y;
private double ancho;
private double largo;
//funciones miembro o mtodos
public Rectngulo (double w, double h)
{
x = 0;
y = 0;
ancho = w;
largo = h;
}
public Set_Rectngulo(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.
Adems de las variables de instancia hay variables de clase. Se explicarn con detalle
ms adelante, en este mismo captulo.

7/35

Marco Besteiro y Miguel Rodrguez

Clases

Mtodos.
Forma general
Los mtodos de una clase son porciones o bloques de cdigo a los que los objetos de esa
clase pueden llamar para que sean ejecutados. Generalmente operan sobre los campos.
Las clases no tiene limitacin en cuanto al nmero de mtodos. Los mtodos pueden
tener parmetros y devolverlos.
Si un mtodo no devuelve nada, se utiliza la palabra void.
La estructura general de un mtodo es:
[modificadores] tipo_de_retorno nombreDelMetodo (Parmetros_opcionales)
{
//cuerpo del mtodo
}

Los mtodos de un determinado objeto se invocan con el operador punto (.).


Todo mtodo tiene que tener un nombre (nombreDelMetodo); ninguno, uno o varios
parmetros con modificadores tambin 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 ms, ahora se va a explicar nicamente
los que definen mtodo estticos static-.

Miembros estticos
Hay ocasiones en los que un miembro de una clase, ya sea campo o mtodo, hace ms
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 nmero 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
especfico. Para ello, en su definicin, el miembro ha de ir precedido por el modificador
static.
Cuando se declara un miembro como esttico, se puede acceder a l sin haber creado
ningn objeto en particular. Esto es lo que sucede con el mtodo Main() que debe ser
declarado como static porque tiene que ser invocado al inicio del programa, es decir,
cuando todava no se ha creado ningn objeto de ninguna clase. Al tener este
modificador, el mtodo Main() puede ser invocado sin necesidad de crear previamente
ningn 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 razn, este tipo de miembros se
denominan campos o mtodos estticos o de clase o , en contraposicin a los mtodos o
campos de objeto o de instancia.

8/35

Marco Besteiro y Miguel Rodrguez

Clases

Fuera de la clase en la que han sido definidos, los mtodos y campos estticos 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 continuacin se propone un ejemplo que puede servir para aclarar este concepto:
Se trata de disear 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 ingeniera 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 Rodrguez

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 esttico, al ser un miembro de clase, hay que
invocarlo a travs del nombre de la clase. En C# no puede llamarse a un mtodo o
campo esttico a travs del nombre del objeto como en Java-, porque dara error. As,
notaIngenieros se manipula en la lnea:
Alumno.notaIngenieros=7;

Una vez ejecutada esta sentencia, el miembro esttico 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 estticos deben inicializarse en la propia clase aunque si no se hace as,
se inicializarn con los valores por defecto.
Los mtodos declarados como static tienen algunas restricciones:
a) Slo pueden llamar a mtodos 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 estticos y ser usada directamente, sin crear objeto
alguno. Mediante el uso de miembros estticos es posible mantener informacin
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 parmetros


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

10/35

Marco Besteiro y Miguel Rodrguez

Clases

reservada. Dicha palabra se debe utilizar tanto en la definicin del mtodo como cuando
se invoca al mtodo. A continuacin se van a estudiar las distintas posibilidades:

Paso por valor: El mtodo recibe una copia del valor almacenado en la
variable original. En su cdigo, el mtodo 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 parmetros que no se
identifica por ninguna palabra reservada.

Por ejemplo:

Paso por referencia: La palabra que identifica este tipo de paso de


parmetros es ref. En este caso, al mtodo se le pasa una referencia del
objeto o la misma variable no una copia-, de tal forma que cualquier
modificacin del objeto o variable se produce en el original porque se trabaja
con ella.
Por ejemplo

Parmetro de salida: La palabra que precede al parmetro es out.


Bsicamente, es igual al paso por referencia, aunque en este caso el valor que
se pasa al mtodo no tiene ninguna importancia, porque ese parmetro 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 parmetro
en el cuerpo del mtodo- antes de utilizarlo. En caso contrario el compilador
generar una excepcin. No se puede tampoco consultar antes de haberle
asignado uno en el propio cuerpo del mtodo.
Por ejemplo:

Listas variables de parmetros: La palabra que identifica este paso es


params. params debe ir seguida del tipo de parmetro y los corchetes []
vacos, que declaran que se desconoce el nmero de parmetros que se va a
pasar. Si los parmetros 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 cmo comunicarse con el coche
acelerar para aumentar la velocidad, girar el volante para cambiar de direccin, etc-. Le
es suficiente con saber cmo utilizar un objeto de esa clase (es decir, cmo comunicarse
con l) para utilizarlo.
Para proteger a los miembros de una clase de modificaciones no deseadas y para
garantizar que tomen valores lgicos y acordes con la naturaleza misma de los datos, se
introduce el concepto de encapsulacin de los datos. Por esta razn, 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 Rodrguez

Clases

En lneas muy generales, se puede decir que la encapsulacin consiste en definir los
campos de datos como privados para protegerlos y los mtodos como pblicos para que
puedan manipular los datos. En general, la encapsulacin es una manera comn de
escribir el cdigo 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
pblicos 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 mtodos pblicos 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 implementacin de la clase. Le es suficiente con conocer cmo
se utilizan los mtodos pblicos: qu mensajes se pueden enviar al objeto a travs de
ellos, y cmo 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 pblicos 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 lneas darn error al compilar
clase.a = 10;
clase.b = 11;
//Los objetos de UnaClase pueden acceder
//a los miembros pblicos 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 Rodrguez

Clases

}
}

Las lneas
clase.a = 10;
clase.b = 11;

no pueden compilarse deben ser comentadas para que el proceso de compilacin 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 slo
se pueden manipular, invocar o llamar desde el mismo cdigo de definicin de la clase.
Se puede decir que las funciones miembro de la clase UnaClase pueden acceder a
miembros pblicos y privados de la clase.
Los objetos de la clase UnaClase pueden acceder slo a miembros pblicos de
UnaClase, como puede verse en las siguientes lneas:
clase.c = 12;
clase.Imprimir();

Sin embargo los miembros de la clase pueden acceder a los miembros pblicos y
privados de la clase, pero siempre desde el interior desde el propio cdigo de
definicin- de la clase. Por ejemplo, vemos que el mtodo Imprimir() puede acceder
sin problemas a los miembros de la clase.
La salida del programa es a=0,b=0, c=12;

Sobrecarga de mtodos
Muchas veces se ha utilizado en este libro la sobrecarga de mtodos pero sin decirlo
explcitamente. 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 cdigo puede ser:


String unaCadena = Hola Mundo;
Console.WriteLine(unaCadena};

Cmo es esto posible? Porqu el mtodo Console.WriteLine() toma dos


parmetros de tipo distinto?
Si el mtodo espera un string en el primero de los casos generara un error al compilar
porque no se realiza un casting implcitamente de int a string. Es parecido lo que
ocurrira en el segundo de los casos.
La explicacin es que hay dos mtodos diferentes de nombre Console.WriteLine(),
uno de los cuales toma como parmetro un entero y el otro una cadena. Incluso, se
puede utilizar este mtodo con un nmero de parmetros diferente. Por ejemplo:
13/35

Marco Besteiro y Miguel Rodrguez

Clases

String unaCadena = Hola Mundo;


Console.WriteLine(La cadena es {0,},unaCadena};

En C#, como en otros lenguajes de programacin orientada a objetos, se puede


sobrecargar mtodos. La sobrecarga de mtodos consiste en declarar y definir varios
mtodos distintos con el mismo nombre. Cada uno de estos mtodos se define de forma
diferente. En el momento de la ejecucin el compilador llama a uno u otro dependiendo
del tipo de los argumentos del mtodo y/o del nmero de parmetros 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 mtodo es necesario que los dos mtodos difieran al menos en el
tipo de alguno de sus argumentos o en el nmero 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 Rodrguez

Clases

En este ejemplo se observa cmo el compilador puede distinguir el cdigo que debe
utilizar porque el tipo de argumento es diferente en los dos mtodos. En el siguiente
ejemplo, el compilador puede distinguirlos porque el nmero de argumentos que utiliza
en las llamadas es diferente aunque en este caso tambin 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 ms adelante, los operadores se pueden tambin sobrecargar, aunque


tienen una estructura un poco diferente a la sobrecarga de mtodos.

Constructores.
El constructor es un mtodo 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 pblico
c) No tener ningn retorno ni siquiera void-.
Realmente, lo que ocurre es que inmediatamente despus de que se crea el objeto, el
compilador invoca al constructor. El funcionamiento es igual que un mtodo. En el
ejemplo de la clase Rectngulo, ya se ha utilizado un constructor de la clase.
public Rectngulo (double w, double h)
{

15/35

Marco Besteiro y Miguel Rodrguez

Clases

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

Para crear un objeto de la clase Rectangulo se utilizaba la instruccin:


Rectangulo unRect = new Rectangulo(55,44);

Esta sentencia, despus de reservar memoria para el objeto para cada uno de sus
campos- ejecuta el cdigo del constructor. Inicializa los campos x, y, ancho y largo
con los valores 0,0, 55 y 44 respectivamente.
Adems se puede distinguir entre los constructores de instancia y los constructores
estticos (static).
Los constructores de instancia implementan las acciones necesarias para inicializar las
instancias de la clase, es decir, los objetos. Los constructores estticos (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 mtodo. Se
puede escribir para una clase tantos constructores como se desee. Sin embargo, los
constructores deben diferenciarse entre s o en el nmero de parmetros o al menos, en
el tipo de parmetro. El compilador en tiempo de ejecucin diferenciar entre ellos y
utilizar el que se ajuste en nmero 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 Rodrguez

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 Rodrguez

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 Rectngulo() si no se hubiera sobrecargado.

Inicializacin de miembros por defecto


Si no se define ningn constructor, el compilador define un constructor
denominado constructor por defecto. Dicho constructor no tiene cdigo ni
parmetros. Su nica misin 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 Rodrguez

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} aos.", 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 cdigo de una clase al propio objeto, se utiliza this, que es una
referencia implcita al propio objeto.
Por ejemplo:
class Rectngulo
{
int ancho;
int largo;
public Rectngulo(int ancho, int largo)

19/35

Marco Besteiro y Miguel Rodrguez

Clases

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

En este ejemplo, los parmetros 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 cdigo sea ms legible, se utiliza this.

Destructores y recolector de basura.


Los destructores contienen el cdigo 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 smbolo ~ (ALT+126)
El funcionamiento de los destructores no se parece al de C++. Realmente, es el cdigo
que se ejecuta cuando un objeto se destruye. Es muy parecido al mtodo 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 mtodo finalize. Se mantiene por comodidad al
migrar.

Propiedades.
Las propiedades constituyen una importante aportacin 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 diseador de la VCL que es la librera en la que se
apoyan estos dos estupendas herramientas visuales de programacin.
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. Adems, las
propiedades permiten dotar a los campos de la caracterstica 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 Rodrguez

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 cmo se asignan valores 10 y 25- a los campos
pblicos Ancho y Largo del objeto unRect. La asignacin 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 pblicos 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
tendra sentido.
El hecho de controlar los procesos de lectura y escritura es muy importante. Se puede
hacer escribiendo mtodos apropiados y de hecho, en los lenguajes orientados a objetos
se vena haciendo as hasta ahora. Sin embargo, esto puede ser, en ocasiones, tedioso.
Las propiedades constituyen una manera fcil y elegante de hacerlo.
La declaracin 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 cdigo 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. Adems 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 Rodrguez

Clases

{
return nombre;
}
}

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

El acceso set contiene el cdigo que se ha de ejecutar al escribir en la propiedad y por


lo tanto en un campo. El parmetro value es el valor que se le da a la propiedad.
Generalmente en este campo se suele implementar el cdigo de validacin 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 Rodrguez

Clases

if(value<0)
ancho=0;
else
ancho=value;
}
}
public int Largo
{
get
{
return largo;
}
set
{
if(value<0)
largo=0;
else
largo=value;
}
}
}
class MiAplicacion
{
static void Main(string[] args)
{
Rectangulo unRect=new Rectangulo(13,26);
unRect.Ancho=10;
unRect.Largo=25;
Console.WriteLine("Ancho={0}, Largo={1}",
unRect.Ancho,unRect.Largo);
}
}
}

Realmente el cdigo es el mismo que el anterior, pero se permite la proteccin de los


datos de la clase y adems se controla la asignacin de valores a los campos.
Las propiedades permiten ocultar detalles de la implementacin, pero tambin permiten
establecer el hecho de que un campo sea de slo lectura o de slo escritura.
Esto se consigue de la siguiente manera:
a) Para establecer un campo como de slo lectura se debe implementar nicamente
el acceso get.
b) Para establecer un campo como slo de escritura se debe implementar slo el
acceso set.
c) Para establecer un campo como de lectura y escritura se debe implementar los
accesos get y set.
Por ejemplo:
using System;
namespace Accesos
{

23/35

Marco Besteiro y Miguel Rodrguez

Clases

class Persona
{
string nombre;
string direccion;
public Persona(string str)
{
nombre=str;
}
public string Direccion
{
get
{
return direccion;
}
set
{
direccion=value;
}
}
//Definimos una propiedad de slo lectura
public string Nombre
{
get
{
return nombre;
}
}
}
class AccesosApp
{
static void Main(string[] args)
{
Persona p=new Persona("Patricia");
//ERROR en la siguiente lnea.
//El campo es de solo lectura
//unaPersona.Nombre="Juan";
p.Direccion="Gran Va 66";
Console.WriteLine("Nombre={0}, Direccion={1}",
p.Nombre,p.Direccion="Gran Va 66");
}
}
}

La lnea
unaPersona.Nombre="Juan";

est comentada porque es una propiedad de slo lectura. No puede escribirse ningn
dato en la propiedad. Slo se puede hacer al crear el objeto, a travs del constructor.
A continuacin se proponen una serie de ejemplos que tienen que ver con la herencia y
con la sobrecarga. Si el lector no conoce estos dos temas, es mejor que los deje para una
lectura posterior.
Ejemplo
using System;
public class ClaseBase

24/35

Marco Besteiro y Miguel Rodrguez

Clases

{
private string nombre;
public string Nombre
{
get
{
return nombre;
}
set
{
nombre = value;
}
}
}
public class ClaseDerivada : ClaseBase
{
private string nombre;
// importante: se utiliza el modificador new
// mas adelante se explica el significado de este modificador
public new string Nombre
{
get
{
return nombre;
}
set
{
nombre = value;
}
}
}
public class ClasePrincipal
{
public static void Main()
{
ClaseDerivada d = new ClaseDerivada ();
d.Nombre = "Germn"; // Propiedad de la clase derivada
Console.WriteLine("Nombre en la clase derivada: {0}",d.Nombre);
((ClaseBase)d).Nombre="Itxaso"; // Propiedad de la clase base
Console.WriteLine("Nombre en la clase base: {0}",
((ClaseBase)d). Nombre);
}
}

Ejemplo 2:
using System;
namespace Accesos
{
abstract class Figura
{
public abstract double Area
{
get;
set;
}

25/35

Marco Besteiro y Miguel Rodrguez

Clases

}
class Cuadrado: Figura
{
public double lado;
// Constructor:
public Cuadrado(double s)
{
lado = s;
}
// Propiedad Area
public override double Area
{
get
{
return lado * lado;
}
set
{
// Dado el area, se calcula el lado
lado = Math.Sqrt(value);
}
}
}
class Cubo: Figura
{
public double lado;
// Constructor:
public Cubo(double s)
{
lado = s;
}
// Propiedad Area
public override double Area
{
get
{
return 6*lado*lado;
}
set
{
// Dado el area, calcula el lado
lado = Math.Sqrt(value/6);
}
}
}
public class ClasePrincipal
{
public static void Main()
{
// Introducir el lado:
Console.Write("Introduce el lado: ");
string ladoString = Console.ReadLine();
double lado = double.Parse(ladoString);

26/35

Marco Besteiro y Miguel Rodrguez

Clases

// Calculo de las areas:


Cuadrado s = new Cuadrado(lado);
Cubo c = new Cubo(lado);
// Imprime los resultados en pantalla:
Console.WriteLine("Area Cuadrado={0}",s.Area);
Console.WriteLine("Area Cubo={0}",c.Area);
// Introducir el area:
Console.Write("Introduzca el area: ");
string areaString = Console.ReadLine();
double area = double.Parse(areaString);
// Calcular areas:
s.Area = area;
c.Area = area;
// Imprime los resultados en pantalla:
Console.WriteLine("Lado del cuadrado={0}", s.lado);
Console.WriteLine("Lado del Cubo = {0}", c.lado);
}
}
}

Indexadores.
Permiten indexar las instancias de una clase o estructura del mismo modo que un array.
Un indexador es una variante de una propiedad que admite un ndice. Normalmente se
utiliza para asociar cada elemento de la clase o estructura a la que pertenece con cada
posible valor del ndice. No obstante, se puede programar como se desee la respuesta
que se de al uso del indexador.
Supngase una clase PuntoEspacial cuya definicin es:
class PuntoEspacial
{
public int x, y, z;
...
...
...
}

La manera de utilizar sus instancias sera, por ejemplo:


PuntoEspacial punto1;
punto1.x = 5;
punto1.y = 6;
punto1.z = 10;

Mediante un indexador, es posible asociar el ndice 0 a x, el 1 a y y el 2 a z, de


modo que:
punto1[0] = 5; equivalga a hacer punto1.x = 5;
punto1[1] = 6; equivalga a hacer punto1.y = 6;

27/35

Marco Besteiro y Miguel Rodrguez

Clases

y
punto1[2] = 10; equivalga a hacer punto1.x = 10;

La clase PuntoEspacial con el indexador, quedar como sigue:


class PuntoEspacial
{
public int x, y, z;
public int this [int indice]
{
get
{
switch (indice)
{
case 0: return x;
break;
case 1: return y;
break;
case 2: return z;
break;
default: System.Console.WriteLine
est fuera del rango permitido);
}
}
set
{
switch (indice)
{
case 0: x = value;
break;
case 1: y = value;
break;
case 2: z = value;
break;
default: System.Console.WriteLine
est fuera del rango permitido);
}
}
}

(El

ndice

(El

ndice

Como puede observarse, el modo de declarar el indexador es:


public int this [int indice]

que quiere decir que es una propiedad pblica, que recibe un ndice y puede recibir
(set) o devolver un entero (get). En realidad, excluyendo el hecho de que recibe un
ndice, el indexador es una propiedad normal. Si se utiliza para una asignacin (value
representa el valor asignado) se ejecuta set y si se utiliza para obtener el valor de un
elemento de la clase se ejecuta el mtodo get.

28/35

Marco Besteiro y Miguel Rodrguez

Clases

Operadores.
Los operadores se han venido utilizando hasta ahora, se pueden sobrecargar, de tal
manera que si, por ejemplo, z1 y z2 son dos nmeros complejos, de manera automtica
el compilador entienda que z1 + z2 es la suma de dos nmeros complejos y por lo
tanto debe sumar de una manera diferente.
Los operadores que se pueden sobrecargar son:
+ - ! ~ ++ -- True False
+ - * / % & | ^ << >> == != > < >= <=

En C# es muy sencillo sobrecargar un operador y la sobrecarga es muy parecida a la de


C++.
Ejemplo: a continuacin se va a sobrecargar el operador binario + para la clase
Complejo, de modo que sea posible sumar dos objetos de esta clase.
using System;
namespace NameSpaceDeComplejos
{
public class Complejo
{
public int real = 0;
public int im = 0;
public Complejo(int real, int im)
{
this.real = real;
this.im = im;
}
public static Complejo operator +(Complejo c1, Complejo c2)
{
Complejo temporal=new Complejo(c1.real+c2.real,
c1.im + c2.im);
return temporal;
//podra haberse hecho as
//return new Complejo(c1.real + c2.real,
//
c1.im + c2.im);
}
public static void Main()
{
Complejo z1 = new Complejo(2,3);
Complejo z2 = new Complejo(3,4);
Complejo z = z1 + z2;
Console.WriteLine("Parte Real: {0}", z.real);
Console.WriteLine("Parte imaginaria: {0}", z.im);
}
}
}

29/35

Marco Besteiro y Miguel Rodrguez

Clases

La lnea ms importante es:


public static Complejo operator +(Complejo c1, Complejo c2)

Para sobrecargar un operador:


a) El mtodo debe ser public.
b) Debe ser static.
c) Se debe indicar qu tipo devuelve. En general devolver un tipo igual a los que
se est operado, para poder concatenar dicha operacin: por ejemplo, podra
realizarse una operacin z1 + z2 + z3.
d) Se debe indicar siempre la palabra reservada operator seguida del operador que
se vaya a sobrecargar.
e) Entre parntesis el o los operandos, especificando sus tipos que se vaya a
utilizar. Si el operador es unario, slo tendr un operando.
Se propone al lector que complete la clase Complejo sobrecargando el resto de las
operaciones binarias (resta, producto y divisin de nmeros complejos) y sobrecargue
algn operador unario, por ejemplo ++ (se podra sobrecargar de tal manera que
aumente en una unidad la parte real y deje igual la parte imaginaria). Puede tambin ser
interesante sobrecargar el operador ==, para comparar dos nmeros complejos.

Modificadores de clase.
Los modificadores de una clase pueden ser:
new
abstract
sealed
public
protected
internal
private

new.
Es posible definir una clase en el interior de otra. Esto es til muchas veces para
ocultarla o bien porque nos interesa utilizarla como miembro de la clase que la contiene.
Esto es muy habitual en la programacin visual.
El modificador new slo se permite en clases anidadas. Indica que la clase oculta un
miembro heredado con el mismo nombre que aquel al que afecta new. En una
declaracin de clase se permite declarar un miembro con el mismo nombre y parmetros
que otro heredado. En tal caso se dice que el miembro derivado esconde al miembro
de la clase base. Ante la situacin comentada el compilador muestra un aviso o
warning. Si se quiere evitar tal aviso ha de precederse la declaracin del nuevo
miembro con el modificador new.
Ejemplo:

30/35

Marco Besteiro y Miguel Rodrguez

Clases

public class MiClaseBase


{
public int x;
public void UnaFuncion();
}
public class MiClaseDerivada : MiClaseBase
{
new public void UnaFuncion ();
//mas codigo
}

No se debe utilizar new y override en la misma declaracin, ya que dar un error de


compilacin. Se ha realizado un ejemplo cuando se han explicado las propiedades.
Ejemplo:
using System;
public class MiClaseBase
{
public static int x = 55;
public static int y = 22;
}
public class MiClaseDerivada: MiClaseBase
{
//El miembro ocultaria al de la clase base sin el modificador new
new public static int x = 100;
public static void Main()
{
// Imprime en pantalla el valor de x de la clase derivada
Console.WriteLine(x);
// Acceso al valor oculto x de la clase base:
Console.WriteLine(MiClaseBase.x);
// Imprime en pantalla el valor de y, que no est oculto
Console.WriteLine(y);
}
}

Modificadores de visibilidad o de acceso


Los modificadores public, protected, internal y private son modificadores de
control de acceso a la clase. Estos modificadores determinan la visibilidad de un
miembro de una clase. Se realizar una explicacin detallada de esos modificadores al
estudiar el concepto de herencia.
Su efecto se indica en la tabla 5.1:

Modificador
public
protected

Visibilidad
Acceso Total.
El acceso est permitido a la clase que contiene al miembro y a
sus tipos derivados.
31/35

Marco Besteiro y Miguel Rodrguez

Clases

internal

El acceso est limitado al proyecto actual.


protected internal El acceso est limitado al proyecto actual y a los tipos
derivados de la clase que contiene al miembro.
private
El acceso est limitado al tipo clase que contiene al miembro.
Tabla 5.1
No todos los modificadores pueden utilizarse con todos los tipos, las opciones
permitidas son:

Tipo

Opcin por defecto de acceso a los miembros Opciones permitidas

enum
class

public
private

interface
struct

public
private

None
public
protected
internal
private
protected internal
None
public
internal
private

Tabla 5.2
Por ejemplo:
using System;
namespace MiEspacioDeNombres
{
public class T1
{
public static int unEnteroPublico;
internal static int unEnteroInternal;
private static int unEnteroPrivado = 0;
public class M1
{
public static int unEnteroPublico;
internal static int unEnteroInternal;
private static int unEnteroPrivado = 0;
}
private class M2
{
public static int unEnteroPublico= 0;
internal static int unEnteroInternal = 0;
private static int unEnteroPrivado = 0;
}
}
public class MainClass
{
public static int Main()
{
// Acceso a los campos de T1

32/35

Marco Besteiro y Miguel Rodrguez

Clases

T1.unEnteroPublico=1;
// Acceso ilimitado
T1.unEnteroInternal=2; // Accesible solo en proyecto actual
// T1.unEnteroPrivado=3;// Error:inaccessible fuera de T1
// Acceso a los campos de M1
T1.M1.unEnteroPublico= 1;
// Acceso ilimitado
T1.M1.unEnteroInternal=2;
//Acceso slo en el proyecto
//actual
//T1.M1.unEnteroPrivado=3; // Error: inaccesible fuera de M1
//Acceso a los campos de M2
//T1.M2.unEnteroPublico=1; // Error: inaccesible fuera de T1
//T1.M2.unEnteroInternal=2; // Error: inaccesible fuera de T1
//T1.M2.unEnteroPrivado=3; // Error: inaccesible fuera de M2
return 0;
}
}
}

abstract.
Se denomina clase abstracta a aqulla que contiene uno o ms miembros abstractos.
Este modificador indica que no se pueden crear instancias u objetos de esa clase, porque
no est totalmente implementado. Habitualmente se utilizan para definir el interfaz que
deben heredar todas sus subclases, ya que todas las clases que derivan de ella deben
implementar, de manera obligatoria, todos los mtodos que son abstractos en la clase
base. Pueden crearse objetos de clases derivadas de una clase abstracta.
Para definir una clase como abstracta, debe ir precedida de la palabra abstract
Por ejemplo:
abstract class MiClaseBase
{
//codigo con algun miembro abstracto
}

Entonces, la sentencia
MiClaseBase unaClaseBase=new MiClaseBase();

no se compilara nunca, porque no se pueden crear objetos de una clase abstracta.


Sin embargo, supngase que deriva de esta clase otra por ejemplo MiClaseDerivadaque implementa sus miembros abstractos:
Class MiClaseDerivada : MiClaseBase
{
//codigo
}

33/35

Marco Besteiro y Miguel Rodrguez

Clases

Gracias al polimorfismo de referencias, es posible que una referencia a un objeto de


la clase base, referencie a un objeto de la clase derivada. Esto es cierto, incluso
cuando la clase base es abstracta o un interface.
Por esta razn, el siguiente cdigo, en la aplicacin principal es perfectamente vlido:
MiClaseBase unaRefBase;
MiClaseDerivada unaRefDerivada = new MiClaseDerivada();
UnaRefBase = unaRefDerivada;

O bien:
MiClaseBase unaRefBase = new MiClaseDerivada();

En el siguiente ejemplo se ha definido una clase abstracta, con una propiedad abstract.
Cuando se sobrescribe un miembro abstracto, basta con precederlo de la palabra
override. Es decir, para sobrescribir un miembro, ste debe ir precedido o modificado
por las palabras reservadas abstract si es que no lo implementa- o virtual si lo
implementa-. Esto es lo que sucede con el miembro MiMetodo().
Ejemplo:
using System;
abstract class MiClaseBase
// Clase Abstracta
{
protected int x = 100;
protected int y = 150;
public abstract void MiMetodo();
// Metodo abstracto
public abstract int GetX
{
get;
}

//Propiedad abstracta

public abstract int GetY


{
get;
}

// Propiedad abstracta

}
class MiClaseDerivada: MiClaseBase
{
public override void MiMetodo()
{
x++;
y++;
}
public override int GetX
{
get
{
return x+10;
}
}

// overriding property

public override int GetY


{

// overriding property

34/35

Marco Besteiro y Miguel Rodrguez

Clases

get
{
return y+10;
}
}
public static void Main()
{
MiClaseDerivada mC = new MiClaseDerivada ();
mC.MiMetodo();
Console.WriteLine("x = {0}, y = {1}", mC.GetX, mC.GetY);
}
}

sealed.
El modificador sealed hace que la clase a la que modifique no pueda ser derivada.
Algunas clases que se suministran con la librera .NET utilizan este modificador.
Ejemplo:
using System;
sealed class MiClaseCerrada
{
public int x;
public int y;
}
class MainClass
{
public static void Main()
{
MiClaseCerrada mC = new MiClaseCerrada();
mC.x = 110;
mC.y = 150;
Console.WriteLine("x = {0}, y = {1}", mC.x, mC.y);
}
}

35/35

También podría gustarte