Академический Документы
Профессиональный Документы
Культура Документы
Este capítulo introduce a las clases en C++. La clase es la fundación de C++ para el soporte
de la programación orientada a objetos, y se encuentra en el núcleo de muchas de sus más
avanzadas características. La clase es la unidad básica de C++ de la encapsulación y esta
provee el mecanismo por el cual los objetos son creados.
Fundamentos de Clases
Vamos a comenzar definiendo los términos de clase y objeto. Una clase define un nuevo
tipo de dato que especifica la forma de un objeto. Una clase incluye los datos y el código
que operará sobre esos datos. Además, una clase enlaza datos y código. C++ usa una
especificación de una clase para construir objetos. Los objetos son instancias de una clase.
Además, una clase es esencialmente una serie de planes que especifican cómo construir
un objeto. Es importante tener claro esto: Una clase es una abstracción lógica.
No es sino hasta que un objeto de esa clase sea creado que la representación física de la
clase existe en la memoria. Cuando se define una clase, se declaran los datos que ésta
contiene y el código que opera en esos datos. Aunque clases muy simples pueden contener
sólo código o sólo datos, la mayoría de las clases contienen ambos. En conjunto, los datos
se almacenan en las variables y el código en las funciones. Colectivamente, las funciones y
variables que constituyen una clase son llamados 'miembros' de la clase. Una variable
declarada dentro de una clase es llamada 'variable miembro', y una función declarada en
una clase es llamada 'función miembro'. En ocasiones el término 'variable de instancia' es
usado en lugar de variable miembro.
Una clase es creada con la palabra clave class. La declaración de una clase es similar
sintácticamente a una estructura (y tienen muchísimo que ver). Aquí tenemos un ejemplo.
La siguiente clase define un tipo llamado CRender, el cual es usado para implementar
operaciones de renderizado en este caso.
Cuando un objeto de la clase es creado, éste tendrá su propia copia de las variables
miembros que contiene la clase. Esto significa que render1 y render2 tendrán su propia e
independiente copia de buffer. Los datos asociados con render1 son distintos y separados
de los datos asociados con render2.
Recordemos: En C++, una clase es un nuevo tipo de dato que puede ser usado para crear
objetos. Específicamente, una clase crea una consistencia lógica que define una relación
entre sus miembros. Cuando se declara una variable de una clase, se está creando un
objeto. Un objeto tiene existencia física, y es una instancia específica de una clase. ( Esto
es, un objeto ocupa espacio de memoria, pero una definición de tipo no ). Además, cada
objeto de una clase tiene su propia copia de los datos definidos dentro de esa clase.
Dentro de la declaración de CRender, el prototipo de una función es especificado. Ya que
las funciones miembros son prototipadas dentro de la definición de la clase, no necesitan
ser prototipadas en otro lugar cualquiera.
Para implementar una función que es un miembro de una clase, debe indicarle al compilador
a cual clase pertenece la función calificando el nombre de la función con el nombre de la
clase. Por ejemplo, esta es una manera de codificar la función m_Renderizar().
void CRender::m_Renderizar()
{
strcpy(buffer, "C++ en wikibooks");
return;
}
Resolución de ámbito[editar]
objeto1.m_Renderizar();
// Programa OPP01.CPP
#include <iostream>
#include <cstring>
using std::cout;
using std::endl;
return (0);
}
Miembros:
A partir de este momento usaremos la palabra miembro para referirnos al hecho de
que un método o un atributo pertenece a tal o cual clase.
Por Ejemplo, en el programa OOP01.CPP (visto anteriormente) la
Clase CRender posee dos miembros, buffer que es un atributo; y m_Renderizar
que es un método.
class CRender {
public:
char buffer[256]; // atributo
void m_Renderizar(const char *cadena); // método
};
class Pareja
{
// atributos
double a, b;
public:
// métodos
double getA();
double getB();
void setA(double n);
void setB(double n);
};
// implementación de los métodos de la clase Pareja
//
double Pareja::getA() { return a; }
double Pareja::getB() { return b; }
void Pareja::setA(double n) { a = n; }
void Pareja::setB(double n) { b = n; }
Subclases
Una subclase es una clase que se deriva de otra. La clase que sirve de base
suele conocerse como parent (padre), y a la subclase se le llama child (hija).
En C++ cada clase que es creada se convierte en candidata para servir de base
de donde se deriven otras. Por ejemplo, la clase Pareja es candidata para
convertirse en la base para las subclases Suma, Resta, Multiplica, Divide, y
otras posibles subclases en donde se utilice un par de valores numéricos.
Para poner un ejemplo, pensemos en que deseamos crear la clase Suma,
misma que será utilizada para obtener la suma de dos números. Puesto que la
clase Pareja posee dos atributos númericos puede ser usada como base para
la clase que estamos proyectando. Así, el siguiente ejemplo se constituye en un
caso de clases derivadas.
public:
// métodos de Suma
double calcular();
};
// implementación de Suma
//
double Suma::calcular() { return getA() + getB(); }
Probando las clases Pareja y Suma
// programa OOP02.CPP
// Este programa pone a prueba el uso de las clase Suma,
// misma que es una subclase de la clase Pareja (ambas definidas
anteriormente).
#include <iostream.h>
int main()
{
Suma s;
s.setA(80);
s.setB(100);
cout << s.getA() << " + " << s.getB() << " = " <<
s.calcular() << endl;
cin.get();
return 0;
}
Herencia[editar]
La herencia es uno de los mecanismos más útiles de la programación orientada
al objeto, ya que por medio de la misma se puede llevar a cabo la reutilización
de código. Es decir, puesto que toda clase definida se convierte en candidata
para ser usada como base de donde se deriven otras, esto da como resultado
que las clases derivadas hereden todos los miembros de la clase base. Por
ejemplo, la clase Suma vista en la sección anterior, hereda todos los miembros
de la clase Pareja puesto que Suma es una extensión de Pareja. En ese
sentido, podemos decir que existen dos tipos de herencia, por extensión y
por agregación o composición. En el caso de las clases Pareja y Suma, se
dice que Suma es una extensión de Pareja. Vista gráficamente, la herencia por
extensión se puede representar así:
Herencia por extensión
Herencia
Al tipo de diagrama mostrado arriba (Herencia por extensión) se le conoce
como UML [1] y es utilizado para mostrar de forma grafica la relación existente
entre una clase hija con la clase padre. En el caso del ejemplo, se muestra que
la clase Suma es una extensión de la clase Pareja y, en consecuencia, Suma
posee a los miembros { a, b, getA(), getB(), setA(), setB() } heredados de la
clase Pareja. Observe como la clase Suma posee otros dos miembros no
heredados, { resultado, y calcular() }, y es precisamente a este tipo de
situación por lo que se dice que Suma es una extensión de Pareja, ya que
Suma, además de poseer a todos los miembros de Pareja, se extiende para
poseer o adquirir otros dos miembros.
Agregacion o composición
La composición se da en los casos en donde una clase posee un objeto que es
una instancia de otra clase. Por ejemplo, la clase Suma podría escribirse de la
siguiente forma:
class Suma
{
// atributo privado
double resultado;
public:
// método público
double calcular();
// atributo público
Pareja p;
};
// implementación del metodo calcular de la clase Suma.
double Suma::calcular() { return p.getA() + p.getB(); }
// programa herencia_por_composicion.CPP
#include <iostream>
using namespace std;
class Pareja
{
// atributos
double a, b;
public:
// métodos
double getA();
double getB();
void setA(double n);
void setB(double n);
};
class Suma
{
// atributo privado
double resultado;
public:
// método público
double calcular();
// atributo público
Pareja p;
};
// implementación del metodo calcular de la clase Suma.
double Suma::calcular() { return p.getA() + p.getB(); }
int main()
{
Suma s;
s.p.setA(80);
s.p.setB(100);
cout << s.p.getA() << " + " << s.p.getB() << " = " <<
s.calcular() << endl;
cin.get();
return 0;
}
////SALIDA////
80 + 100 = 180
Constructores
Un constructor es un método que pertenece a una clase y el cual (en C++) debe
tener el mismo nombre de la clase a la que pertenece. A diferencia de los otros
métodos de la clase, un constructor deberá ser del tipo void, es decir, el mismo
no regresará valor alguno. Una clase puede tener más de un método
constructor. Cada clase debe tener al menos un constructor, tanto así que si el
programador creador de una clase no define un método constructor para la
misma, el sistema, o sea el compilador, creará de manera automática un
constructor nulo.
El objetivo principal del constructor es establecer las condiciones necesarias
dentro de la memoria y crear una copia del objeto mismo dentro de la memoria.
Los constructores suelen usarse para la inicialización de los atributos de los
objetos instanciados. Por ejemplo, con las instrucciones:
Suma s;
s.setA(80);
s.setB(100);
// programa OOP04.CPP
// Ejemplo: clases Pareja y Suma, ambas con constructor
#include <iostream>
using namespace std;
//------------------------
class Pareja
{
// atributos
double a, b;
public:
// constructor de base (null)
Pareja() {}
// constructror parametrizado
Pareja(double x, double y) : a(x), b(y) {}
// métodos
double getA();
double getB();
void setA(double n);
void setB(double n);
};
//------------------------
class Suma : public Pareja
{
// atributos de Suma
double resultado;
public:
// constructor
Suma(double a, double b) : Pareja(a, b) {}
// métodos de Suma
double calcular();
};
// implementación de Suma
//
double Suma::calcular() { return getA() + getB(); }
//------------------------
int main()
{
Suma s(80, 100);
cout << s.getA() << " + " << s.getB() << " = " <<
s.calcular() << endl;
cin.get();
return 0;
}
Destructores
Un destructor es un método que pertenece a una clase y el cual (en C++) debe
tener el mismo nombre de la clase a la que pertenece. A diferencia de los otros
métodos de la clase, un destructor deberá ser del tipo void, es decir, el mismo
no regresará valor alguno. Para diferenciar a un método destructor de un
método constructor, al nombre del destructor se le debe anteponer el
caracter ~ (Alt + 126).
El objetivo principal del destructor es el de retirar de la memoria al objeto, o sea,
el destructor hace todo lo contrario que el constructor.
Los destructores suelen usarse para liberar memoria que haya sido solicitada
por el objeto a través de las ordenes malloc(), new, etc. En tales casos se
deberá incluir dentro del método destructor la orden free, delete, etc., según
sea el caso.
public:
// constructor de base (nulo)
Pareja() {}
// constructor parametrizado
Pareja(double x, double y) : a(x), b(y) {}
// destructor
~Pareja() {}
// métodos
double getA();
double getB();
void setA(double n);
void setB(double n);
};