lunes, 11 de abril de 2016

4.5 Reutilización del código

Lo primero que se les viene a la cabeza a los estudiantes cuando se les menciona la reutilización del código es el famoso copiar y pegar al que se han acostumbrado en la programación estructurada, y de hecho muchos lo hacen en poo, lo cual es una de las practicas que más encarece el desarrollo de software. Como todo en Java, el problema se resuelve con las clases. Para reutilizar el código creamos nuevas clases pero, en lugar de partir de cero, partimos de clases, relacionadas con nuestra clase, que han sido ya creadas y depuradas. El truco está en usar las clases sin ensuciar el código existente.

Una forma de hacer esto es crear objetos de nuestras clases existentes dentro de la nueva clase. Esto se conoce como composición porque la nueva clase está compuesta de objetos de clases existentes. Estamos reutilizando la funcionalidad del código, y no la forma.

Otra forma es crear una nueva clase como un tipo de una clase ya existente. Tomamos la forma de la clase existente y añadimos código a la nueva, sin modificar la clase existente. Esta forma de crear nuevos objetos se llamada herencia, y lo que hacemos es extender la clase en la que nos basamos para crear la nueva.

Composición
 
Hasta ahora hemos usado la composición de cierta manera, ej. cuando hacemos una interfaz gráfica de usuario, nuestra clase de interfaz gráfica esta compuesta por un frame, unos panel, botones, etc. todos estos objetos componen el objeto de interfaz gráfica. Es decir que la composición consiste en poner manejadores de objetos dentro de nuestra clase, estos manejadores de objetos no serán otra cosa que instancias de las clases en las que nos estamos basando para crear la nueva clase.
Recordemos que la forma para determinar cuándo usar composición es cuando podemos decir que nuestra nueva clase “tiene un” elemento de otro tipo de objetos, por ejemplo un cronómetro tiene: horas, minutos y segundos, es decir que una clase Cronometro está compuesta por otras clases llamadas: Horas, Minutos y Segundos.

 Herencia
 
En java aunque no establezcamos de manera explícita la herencia siempre está presente, ya que todas las clases que creemos heredan de la clase Object, por eso es válido decir que en java todo es un objeto. La sintaxis para la composición es obvia pero, para realizar la herencia, hay una forma claramente distinta. Cuando heredamos, estamos diciendo "Esta nueva clase es como esa clase antigua", por ejemplo es decir que la clase Horas “es una” UnidadDeTiempo. Afirmamos esto en el código dando el nombre de la clase como siempre pero, antes de la apertura del límite cuerpo de clase, pondremos la palabra clave "extends" seguida por el nombre de la clase base. Cuando hagamos esto, obtendremos automáticamente todos los datos miembros y métodos de la clase base.
La composición y la herencia
 
Tanto la composición como la herencia permiten poner sub-objetos dentro de tu nueva clase. Podríamos preguntarnos cuál es la diferencia entre los dos, y cuándo elegir uno en lugar del otro. La composición es generalmente usada cuando deseamos las características de una clase existente dentro de una nueva clase, pero no su interfaz. Es decir, ponemos un para poder usarlo para implementar características de nuestra nueva clase, pero el usuario de esa nueva clase verá el interfaz que hemos definido en lugar del interfaz del objeto insertado.

Los objetos miembros usan la implementación ocultándose a sí mismos, por lo que esto es una cosa segura a hacer y, cuando el usuario sabe que estamos uniendo un conjunto de partes, hace que el interfaz sea más fácil de entender.
 
Cuando heredamos, estamos cogiendo una clase existente y creando una versión especial de esa clase. En general, esto significa que estamos tomando una clase de propósito general, especializándola para un caso o necesidad particular. Pensando un poco, podrá entender que no tendría sentido construir un coche usando un objeto vehículo (un coche no contiene un vehículo, ¡es un vehículo!). La relación es- un viene expresada por la herencia, y la relación tiene un viene expresada por la composición.

4.4 Variables polimórficas (plantillas): definición, uso y aplicaciones

En Java, las variables que contienen objetos son variables polimórficas. El término polimórfico  (literalmente: muchas formas) se refiere al hecho de que una misma variable puede contener objetos de diferentes tipos (del tipo declarado o de cualquier subtipo del tipo declarado). El polimorfismo aparece en los lenguajes orientados a objetos en numerosos contextos, las variables polimórficas constituyen justamente un primer ejemplo.

Observemos la manera en que el uso de una variable polimórfica nos ayuda a simplificar nuestro método listar. El cuerpo de este método es:

for (Elemento elemento : elementos)
elemento.imprimir();
 
En este método recorremos la lista de elementos (contenida en un ArrayList mediante la variable elementos), tomamos cada elemento de la lista y luego invocamos su método imprimir.El uso de herencia en este ejemplo ha eliminado la necesidad de escribir dos ciclos en el método listar. La herencia evita la duplicación de código no sólo en las clases servidoras sino también en las clases clientes de aquellas.

public class CD
{
private String title;
private String artist;
private String comment;
CD(String theTitle, String theArtist)
{
title = theTitle;
artist = theArtist;
comment = " ";
}
void setComment(String newComment)
{ ... }
String getComment()
{ ... }
void print()
{ ... }
...
}


public class DVD
{
private String title;
private String director;
private String comment;
DVD(String theTitle, String theDirector)
{
title = theTitle;
director = theDirector;
comment = " ";
}
void setComment(String newComment)
{ ... }
String getComment()
{ ... }
void print()
{ ... }
...
}


class Database {
private ArrayList<CD> cds;
private ArrayList<DVD> dvds;
...
public void list()
{
for(CD cd : cds) {
cd.print();
System.out.println();  }
for(DVD dvd : dvds) {
dvd.print();
System.out.println();  }
}
}

4.3 Interfaces: definición, implementación de interfaces, herencia de interfaces.

Concepto de Interface
El concepto de Interface lleva un paso más adelante la idea de las clases abstractas. En Java una interface es una clase abstracta pura, es dcir una clase donde todos los métodos son abstractos (no se implementa ninguno). Permite al diseñador de clases establecer la forma de una clase (nombres de métodos, listas de argumentos y tipos de retorno, pero no bloques de código). Una interface puede también contener datos miembro, pero estos son siempre static y final. Una interface sirve para establecer un 'protocolo' entre clases. 
Para crear una interface, se utiliza la palabra clave interface en lugar de class. La interface puede definirse public o sin modificador de acceso, y tiene el mismo significado que para las clases. Todos los métodos que declara una interface son siempre public. 
Para indicar que una clase implementa los métodos de una interface se utiliza la palabra clave implements. El compilador se encargará de verificar que la clase efectivamente declare e implemente todos los métodos de la interface. Una clase puede implementar más de una interface.
 
Declaración y uso
Una interface se declara:
interface nombre_interface {
    tipo_retorno nombre_metodo ( lista_argumentos ) ;
    . . .
}
Por ejemplo:
interface InstrumentoMusical {
    void tocar();
    void afinar();
    String tipoInstrumento();
}
Y una clase que implementa la interface:
class InstrumentoViento extends Object implements InstrumentoMusical {
    void tocar() { . . . };
    void afinar() { . . .};
    String tipoInstrumento() {}
}

class Guitarra extends InstrumentoViento {
    String tipoInstrumento() {
        return "Guitarra";
    }
}   
La clase InstrumentoViento implementa la interface, declarando los métodos y escribiendo el código correspondiente. Una clase derivada puede también redefinir si es necesario alguno de los métodos de la interface.
 
Referencias a Interfaces
Es posible crear referencias a interfaces, pero las interfaces no pueden ser instanciadas. Una referencia a una interface puede ser asignada a cualquier objeto que implemente la interface. Por ejemplo:
InstrumentoMusical instrumento = new Guitarra();
instrumento.play();
System.out.prinln(instrumento.tipoInstrumento());

InstrumentoMusical i2 =
new InstrumentoMusical(); //error.No se puede instanciar
 
Extensión de interfaces
Las interfaces pueden extender otras interfaces y, a diferencia de las clases, una interface puede extender más de una interface. La sintaxis es:

interface nombre_interface  extends nombre_interface  , . . . {
    tipo_retorno nombre_metodo ( lista_argumentos ) ;
    . . .
}

4.2 Clases abstractas: definición, métodos abstractos, implementación de clases abstractas, modelado de clases abstractas.

Concepto
Hay ocasiones, cuando se desarrolla una jerarquía de clases en que algún comportamiento está presente en todas ellas pero se materializa de forma distinta para cada una. Por ejemplo, pensemos en una estructura de clases para manipular figuras geométricas. Podríamos pensar en tener una clase genérica, que podría llamarse FiguraGeometrica y una serie de clases que extienden a la anterior que podrían ser Circulo, Poligono, etc. Podría haber un método dibujar dado que sobre todas las figuras puede llevarse a cabo esta acción, pero las operaciones concretas para llevarla a cabo dependen del tipo de figura en concreto (de su clase). Por otra parte la acción dibujar no tiene sentido para la clase genérica FiguraGeometrica, porque esta clase representa una abstracción del conjunto de figuras posibles.
Para resolver esta problemática Java proporciona las clases y métodos abstractos. Un método abstracto es un método declarado en una clase para el cual esa clase no proporciona la implementación (el código). Una clase abstracta es una clase que tiene al menos un método abstracto. Una clase que extiende a una clase abstracta debe implementar los métodos abstractos (escribir el código) o bien volverlos a declarar como abstractos, con lo que ella misma se convierte también en clase abstracta. 
Declaración e implementación de métodos abstractos
Siguiendo con el ejemplo del apartado anterior, se puede escribir:
abstract class FiguraGeometrica {
    . . .
    abstract void dibujar();
    . . .
}

class
Circulo extends FiguraGeometrica {
    . . .
    void dibujar() {
        // codigo para dibujar Circulo
        . . .
    }

La clase abstracta se declara simplemente con el modificador abstract en su declaración. Los métodos abstractos se declaran también con el mismo modificador, declarando el método pero sin implementarlo (sin el bloque de código encerrado entre {}). La clase derivada se declara e implementa de forma normal, como cualquier otra. Sin embargo si no declara e implementa los métodos abstractos de la clase base (en el ejemplo el método dibujar) el compilador genera un error indicando que no se han implementado todos los métodos abstractos y que, o bien, se implementan, o bien se declara la clase abstracta. 
Referencias y objetos abstractos
Se pueden crear referencias a clases abstractas como cualquier otra. No hay ningún problema en poner:
FiguraGeometrica figura;
Sin embargo una clase abstracta no se puede instanciar, es decir, no se pueden crear objetos de una clase abstracta. El compilador producirá un error si se intenta:
FiguraGeometrica figura = new FiguraGeometrica();
Esto es coherente dado que una clase abstracta no tiene completa su implementación y encaja bien con la idea de que algo abstracto no puede materializarse. 
Sin embargo utilizando el up-casting visto en el capítulo dedicado a la Herencia si se puede escribir:
FiguraGeometrica figura = new Circulo(. . .);
figura.dibujar();


La invocación al método dibujarse resolverá en tiempo de ejecución y la JVM llamará al método de la clase adecuada. En nuestro ejemplo se llamará al método dibujarde la clase Circulo.Concepto
Hay ocasiones, cuando se desarrolla una jerarquía de clases en que algún comportamiento está presente en todas ellas pero se materializa de forma distinta para cada una. Por ejemplo, pensemos en una estructura de clases para manipular figuras geométricas. Podríamos pensar en tener una clase genérica, que podría llamarse FiguraGeometrica y una serie de clases que extienden a la anterior que podrían ser Circulo, Poligono, etc. Podría haber un método dibujar dado que sobre todas las figuras puede llevarse a cabo esta acción, pero las operaciones concretas para llevarla a cabo dependen del tipo de figura en concreto (de su clase). Por otra parte la acción dibujar no tiene sentido para la clase genérica FiguraGeometrica, porque esta clase representa una abstracción del conjunto de figuras posibles.
Para resolver esta problemática Java proporciona las clases y métodos abstractos. Un método abstracto es un método declarado en una clase para el cual esa clase no proporciona la implementación (el código). Una clase abstracta es una clase que tiene al menos un método abstracto. Una clase que extiende a una clase abstracta debe implementar los métodos abstractos (escribir el código) o bien volverlos a declarar como abstractos, con lo que ella misma se convierte también en clase abstracta. 
Declaración e implementación de métodos abstractos
Siguiendo con el ejemplo del apartado anterior, se puede escribir:
abstract class FiguraGeometrica {
    . . .
    abstract void dibujar();
    . . .
}

class
Circulo extends FiguraGeometrica {
    . . .
    void dibujar() {
        // codigo para dibujar Circulo
        . . .
    }

La clase abstracta se declara simplemente con el modificador abstract en su declaración. Los métodos abstractos se declaran también con el mismo modificador, declarando el método pero sin implementarlo (sin el bloque de código encerrado entre {}). La clase derivada se declara e implementa de forma normal, como cualquier otra. Sin embargo si no declara e implementa los métodos abstractos de la clase base (en el ejemplo el método dibujar) el compilador genera un error indicando que no se han implementado todos los métodos abstractos y que, o bien, se implementan, o bien se declara la clase abstracta. 
Referencias y objetos abstractos
Se pueden crear referencias a clases abstractas como cualquier otra. No hay ningún problema en poner:
FiguraGeometrica figura;
Sin embargo una clase abstracta no se puede instanciar, es decir, no se pueden crear objetos de una clase abstracta. El compilador producirá un error si se intenta:
FiguraGeometrica figura = new FiguraGeometrica();
Esto es coherente dado que una clase abstracta no tiene completa su implementación y encaja bien con la idea de que algo abstracto no puede materializarse. 
Sin embargo utilizando el up-casting visto en el capítulo dedicado a la Herencia si se puede escribir:
FiguraGeometrica figura = new Circulo(. . .);
figura.dibujar();

La invocación al método dibujarse resolverá en tiempo de ejecución y la JVM llamará al método de la clase adecuada. En nuestro ejemplo se llamará al método dibujarde la clase Circulo.Concepto
Hay ocasiones, cuando se desarrolla una jerarquía de clases en que algún comportamiento está presente en todas ellas pero se materializa de forma distinta para cada una. Por ejemplo, pensemos en una estructura de clases para manipular figuras geométricas. Podríamos pensar en tener una clase genérica, que podría llamarse FiguraGeometrica y una serie de clases que extienden a la anterior que podrían ser Circulo, Poligono, etc. Podría haber un método dibujar dado que sobre todas las figuras puede llevarse a cabo esta acción, pero las operaciones concretas para llevarla a cabo dependen del tipo de figura en concreto (de su clase). Por otra parte la acción dibujar no tiene sentido para la clase genérica FiguraGeometrica, porque esta clase representa una abstracción del conjunto de figuras posibles.
Para resolver esta problemática Java proporciona las clases y métodos abstractos. Un método abstracto es un método declarado en una clase para el cual esa clase no proporciona la implementación (el código). Una clase abstracta es una clase que tiene al menos un método abstracto. Una clase que extiende a una clase abstracta debe implementar los métodos abstractos (escribir el código) o bien volverlos a declarar como abstractos, con lo que ella misma se convierte también en clase abstracta. 
Declaración e implementación de métodos abstractos
Siguiendo con el ejemplo del apartado anterior, se puede escribir:
abstract class FiguraGeometrica {
    . . .
    abstract void dibujar();
    . . .
}

class
Circulo extends FiguraGeometrica {
    . . .
    void dibujar() {
        // codigo para dibujar Circulo
        . . .
    }

La clase abstracta se declara simplemente con el modificador abstract en su declaración. Los métodos abstractos se declaran también con el mismo modificador, declarando el método pero sin implementarlo (sin el bloque de código encerrado entre {}). La clase derivada se declara e implementa de forma normal, como cualquier otra. Sin embargo si no declara e implementa los métodos abstractos de la clase base (en el ejemplo el método dibujar) el compilador genera un error indicando que no se han implementado todos los métodos abstractos y que, o bien, se implementan, o bien se declara la clase abstracta. 
Referencias y objetos abstractos
Se pueden crear referencias a clases abstractas como cualquier otra. No hay ningún problema en poner:
FiguraGeometrica figura;
Sin embargo una clase abstracta no se puede instanciar, es decir, no se pueden crear objetos de una clase abstracta. El compilador producirá un error si se intenta:
FiguraGeometrica figura = new FiguraGeometrica();
Esto es coherente dado que una clase abstracta no tiene completa su implementación y encaja bien con la idea de que algo abstracto no puede materializarse. 
Sin embargo utilizando el up-casting visto en el capítulo dedicado a la Herencia si se puede escribir:
FiguraGeometrica figura = new Circulo(. . .);
figura.dibujar();

La invocación al método dibujarse resolverá en tiempo de ejecución y la JVM llamará al método de la clase adecuada. En nuestro ejemplo se llamará al método dibujarde la clase Circulo.

4.1 Polimorfismo (Definición)



 El polimorfismo es un concepto de la programación orientada a objetos que nos permite programar en forma general, en lugar de hacerlo en forma específica. En general nos sirve para programar objetos con características comunes y que todos estos compartan la misma superclase en una jerarquía de clases, como si todas fueran objetos de la superclase. Esto nos simplifica la programación.

Recuerde el ejemplo del ecosistema, en donde todos los objetos de las distintas especies heredaban de una superclase llamada Animal, que brindaba la información general de cualquier animal, independiente de su especie. Sin embargo, cada especie hace un uso particular de cada uno de los métodos u operaciones de la clase Animal. El método comer() no se ejecutará de la misma manera en un León() o en un Pavo(). Lo mismo ocurre para métodos moverse() en objetos de tipo Tiburón() o Gallina(), aunque todas las especies realicen estos métodos. A la sobrescritura o implementación específica de métodos es la clave del polimorfismo.

Para poner en práctica se hará un ejemplo bastante sencillo. Se hará una librería de clases que represente figuras tridimensionales y bidimensionales, y su respectiva jerarquía de clases. Las clases deben ser capaces de tener funcionamiento bastante básico, como obtener áreas, volúmenes y perímetros de la figura correspondiente.

3.6 Redefinición de métodos en clases derivadas

El lenguaje java permite redefinir miembros de la clase base en las clases derivadas, pero el compilador emite una advertencia cuando detecta una redefinición. Una advertencia (warning) es un mensaje del compilador acerca de un posible problema. Sin embargo, en este caso sí se genera código ejecutable (a diferencia del mensaje de error). Redefinición de campos. El siguiente ejemplo muestra cómo reutilizar los identificadores de los campos de la clase base en una clase derivada.

3.5 Constructores y destructores en clases derivadas.

Constructores en clases derivadas 

Al instanciar objetos de clases derivadas se inicia una cadena de invocaciones a constructores en las cuales el constructor de la clase derivada, antes de realizar sus propias tareas, invoca (ya sea implícita o explícitamente) al constructor de su clase base. Similarmente, si la clase base fue derivada de otra clase, el constructor de la clase base debe invocar al constructor de la clase ubicada en el siguiente nivel superior de la jerarquía, y así sucesivamente. El último constructor invocado en la cadena es el constructor de la clase Object, cuyo cuerpo se ejecuta primero. El cuerpo del constructor de la clase derivada se ejecuta al final. El constructor de cada clase base inicializa las variables de instancia que el objeto de la clase derivada hereda. 

Destructores en clases derivadas 


Cuando remueve de la memoria un objeto de una clase derivada, el recolector de basura invoca al destructor del objeto. Esto inicia una cadena de invocaciones a destructores, en donde el destructor de la clase derivada y los destructores de las clases bases directas e indirectas se ejecutan en orden inverso al que se ejecutaron los constructores, esto es, primero se ejecuta el destructor de la clase derivada y al final se ejecuta el destructor de la clase base ubicada en el nivel superior de la jerarquía. La ejecución de los destructores debe liberar todos los recursos que el objeto adquirió, antes de que el recolector de basura reclame la memoria de ese objeto. Cuando el recolector de basura invoca al destructor de un objeto de una clase derivada, ese destructor realiza su tarea y después invoca al destructor de la clase base. El proceso se repite hasta que se invoca al destructor de la clase Object.

3.4 Referencia al objeto de la clase base

La jerarquía de clases que describen las figuras planas

Consideremos las figuras planas cerradas como el rectángulo, y el círculo. Tales figuras comparten características comunes como es la posición de la figura, de su centro, y el área de la figura, aunque el procedimiento para calcular dicha área sea completamente distinto. Podemos por tanto, diseñar una jerarquía de clases, tal que la clase base denominada Figura, tenga las características comunes y cada clase derivada las específicas. La relación jerárquica se muestra en la figura
La clase Figura es la que contiene las características comunes a dichas figuras concretas por tanto, no tiene forma ni tiene área. Esto lo expresamos declarando Figura como una clase abstracta, declarando la función miembro area abstract.
Las clases abstractas solamente se pueden usar como clases base para otras clases. No se pueden crear objetos pertenecientes a una clase abstracta. Sin embargo, se pueden declarar variables de dichas clases.
En el juego del ajedrez podemos definir una clase base denominada Pieza, con las características comunes a todas las piezas, como es su posición en el tablero, y derivar de ella las características específicas de cada pieza particular. Así pues, la clase Pieza será una clase abstracta con una función abstract denominada mover, y cada tipo de pieza definirá dicha función de acuerdo a las reglas de su movimiento sobre el tablero.


3.3 Reutilización de miembros heredados.

La reutilización de código se refiere al comportamiento y a las técnicas que garantizan que una parte o la totalidad de un programa informático existente se pueda emplear en la construcción de otro programa. De esta forma se aprovecha el trabajo anterior, se economiza tiempo, y se reduce la redundancia.

La manera más fácil de reutilizar código es copiarlo total o parcialmente desde el programa antiguo al programa en desarrollo. Pero es trabajoso mantener múltiples copias del mismo código, por lo que en general se elimina la redundancia dejando el código reusable en un único lugar, y llamándolo desde los diferentes programas. Este proceso se conoce como abstracción. La abstracción puede verse claramente en las bibliotecas de software, en las que se agrupan varias operaciones comunes a cierto dominio para facilitar el desarrollo de programas nuevos. Hay bibliotecas para convertir información entre diferentes formatos conocidos, acceder a dispositivos de almacenamiento externos, proporcionar una interfaz con otros programas, manipular información de manera conocida (como números, fechas, o cadenas de texto).
Para que el código existente se pueda reutilizar, debe definir alguna forma de comunicación o interfaz. Esto se puede dar por llamadas a una subrutina, a un objeto, o a una clase.

Como se ha comentado anteriormente la clase descendiente puede añadir sus propios atributos y métodos pero también puede sustituir u ocultar los heredados. En concreto:
1. Se puede declarar un nuevo atributo con el mismo identificador que uno heredado, quedando este atributo oculto. Esta técnica no es recomendable.
2. Se puede declarar un nuevo método de instancia con la misma cabecera que el de la clase ascendiente, lo que supone su sobreescritura. Por lo tanto, la sobreescritura o redefinición consiste en que métodos adicionales declarados en la clase descendiente con el mismo nombre, tipo de dato devuelto y número y tipo de parámetros sustituyen a los heredados.
3. Se puede declarar un nuevo método de clase con la misma cabecera que el de la clase ascendiente, lo que hace que éste quede oculto. Por lo tanto, los métodos de clase o estáticos (declarados como static) no pueden ser redefinidos.
4. Un método declarado con el modificador final tampoco puede ser redefinido por una clase derivada.
5. Se puede declarar un constructor de la subclase que llame al de la superclase de forma implícita o de mediante la palabra reservada super.
6. En general puede accederse a los métodos de la clase ascendiente que han sido redefinidos empleando la palabra reservada super delante del identificador del método. Este mecanismo sólo permite acceder al metodo perteneciente a la clase en el nivel inmediatamente superior de la jerarquía de clases.

3.2 Clasificación. herencia simple, herencia múltiple.

Herencia 
La herencia es un mecanismo que permite la definición de una clase a partir de la definición de otra ya existente. La herencia permite compartir automáticamente métodos y datos entre clases, subclases y objetos. 
La herencia está fuertemente ligada a la re-utilización del código en la OOP. Esto es, el código de cualquiera de las clases puede ser utilizado sin más que crear una clase derivada de ella, o bien una subclase. 
Hay dos tipos de herencia: Herencia Simple y Herencia Múltiple. La primera indica que se pueden definir nuevas clases solamente a partir de una clase inicial mientras que la segunda indica que se pueden definir nuevas clases a partir de dos o más clases iniciales. Java sólo permite herencia simple.
Herencia Múltiple en Java

Todos sabemos que la herencia es un mecanismo propio de la programación orientada a objetos POO. Nos permite crear clases a partir de otra, las cuales las unen vínculos sumamente estrechos, casi de familia. Es por ello que se llama herencia.


 La herencia múltiple en java no es soportada nativa-mente. Sin embargo muchos autores y desarolladores la simulan utilizando la palabra reservada implements e interfaces, que sirve para implementar o cubrir una clase con respecto a otra.

3.1 Definición: Clase base, Clase derivada.

Clase Base
Una clase base es aquella que no dependen ninguno de sus atributos u objetos de la clase de alguna otra clase, se podría decir que en términos de herencia, seria la clase padre, la clase que se mantiene fija, en el aspecto de herencia.
Es también por así llamarlo la clase principal de un programa, seria la clase primaria sin incluir la clase main en donde se corre todo el programa en si.


Clase Derivada
 son clases que dependen de las clases bases, ya que algunos de sus métodos son también heredados, y muchas veces, el compilador arrojara malos resultados, ya que al ser dependientes estas clases, a veces podrán generar errores lógicos.

3. Herencia




La herencia es específica de la programación orientada a objetos, donde una clase nueva se crea a partir de una clase existente. La herencia (a la que habitualmente se denomina subclases) proviene del hecho de que la subclase (la nueva clase creada) contiene las atributos y métodos de la clase primaria. La principal ventaja de la herencia es la capacidad para definir atributos y métodos nuevos para la subclase, que luego se aplican a los atributos y métodos heredados.