Está en la página 1de 26

UNLaR - APUNTES DE PROGRAMACIÓN

Prof. Ing. Marcelo Daniel Camargo

Programación orientada a objetos (POO)


Este paradigma de programación, se vale de la forma en que los seres humanos modelan al mundo
real.
Los seres humanos han desarrollado capacidades para clasificar, generalizar y abstraer objetos.
La Abstracción se centra en las características esenciales de un objeto, en relación con el punto de
vista del espectador.
Esto les ha permitido tratar e interpretar la complejidad del mundo que les rodea.
Por ej. de un mundo lleno de perros con características distintivas de cada raza, hemos desarrollado
el concepto “perro” como una clase que sintetiza los atributos y el comportamiento que todos los
perros comparten. Esto nos permite desarrollar ideas acerca de los perros, sin pensar en los detalles
de un perro en particular. Esta es la forma como aplicamos la capacidad de clasificar, generalizar y
abstraer.
Entonces la solución “orientada a objetos” de un problema, se logra a través de objetos que
cooperan entre sí para lograr un objetivo. De esta forma el conocimiento se descentraliza en todos
los objetos que lo componen, cada objeto sabe hacer lo suyo y no le interesa saber cómo el vecino
hace su trabajo, pero sabe que lo hace.
Entonces decimos que un objeto, es algo, real o abstracto, que posee características y un conjunto
de operaciones que permiten manipularlo.

Terminología del paradigma


Atributos: son las características de un objeto. Es el conjunto de datos asociados a el. Por ejemplo,
para un objeto de la clase alumno, uno de sus atributos es nombre, y valor es "Juan Paez"; para un
objeto de clase vehículo, uno de sus atributos es ruedas, y su valor es 4. El estado del objeto está
dado por el conjunto de valores de sus atributos en un instante dado. Los objetos variar su estado,
es decir, sus valores de sus atributos (su estado) pueden cambiar durante su período de vida dentro
del programa.
Métodos: son las implementaciones de acciones y/o transformaciones que se le pueden hacer al
objeto.
Propiedades: Se le da este nombre al conjunto de atributos y métodos del objeto.
Identidad: Se refiere a que cada objeto tiene una identidad única, más alla de que comparta el
mismo estado con otro objeto.
Mensaje: es el mecanismo por el cual, se invoca a un método de un objeto. Es decir, la forma que
se le solicita a un objeto que ejecute alguna acción.
Comportamiento: Es la reacción o funcionalidad del objeto a partir de mensajes recibidos en función
de su estado.
Ej.
Se le envía al objeto "a" el mensaje "+=b", resultando
a += b que el objeto a contendrá la suma de los atributos de los
objetos a y b.
Ecapsulamiento: consiste en ocultar los detalles de implementación de un objeto. Dicho de otra
forma, permite el acceso a su estado, únicamente a través de su interface utilizando los métodos
adecuados.
Herencia: es la característica mediante la cual, los objetos pueden valerse de la definición de las
propiedades de otros. Debido a esto, no es necesario redefinirlos en los objetos que los requieran.
Polimorfismo: Permite que métodos con el mismo nombre actuen de acuerdo al objeto que se
aplica. Por ejemplo, el método superficie del tipo de objeto “figura” se resolverá de distinta manera
dependiendo que la figura sea; un triángulo o un rectángulo. La sobrecarga y sobrescritura son
maneras de implementar el polimorfismo, que se abordarán.

- 126 -
UNLaR - APUNTES DE PROGRAMACIÓN
Prof. Ing. Marcelo Daniel Camargo

POO en C++
Es una extensión del lenguaje C (o C ampliado) que proporciona entre otras cosas, las bases para
la programación orientada a objetos.
La programación orientada a objetos en C++, se edifica sobre el concepto de clase.

Clases
Se entiende por clase (class) a un tipo de dato definido por el programador, que contiene la
información (atributos) para construir un objeto de dicho tipo, y el conjunto de procedimientos o
funciones (métodos) que permiten manejarlo. La forma de construir la clase, es la que garantizará
el encapsulamiento del objeto. Las uniones (union) y las estructuras (structs) han sido potenciadas
en C++, permitiendo también la implementación de clases.
Al igual que en las estructuras, a cada uno de los componentes de una clase se los denomina
miembros. A los atributos se los denomina datos miembros y a los métodos funciones miembros.
C++ incorpora, lo que se denomina nivel de acceso, este va a permitir el ocultamiento
(encapsulamiento) de miembros (atributos o métodos) específicos de la clase. Los tres niveles de
acceso que utiliza son:
 public: (Público) Permite acceder al miembro, desde cualquier parte que se pueda acceder
a la clase. Todo miembro público, forma parte de la Interface de la clase.
 private: (Privado). Solo puede accederse a este miembro, mediante métodos declarados
dentro de la misma clase.
 protected: (Protegido). Solo puede accederse a este miembro, mediante métodos
declarados dentro de la misma clase y métodos de clases descendientes.
Tales niveles de acceso estarán presentes en class, struct y union. 17

Sintaxis
La definición de una clase se asemeja mucho a lo que ya hemos visto cuando, definíamos structs.
Esta comienza con la palabra reservada class, a continuación el nombre de la clase y entre llaves
los miembros de la clase categorizados por nivel de acceso. Las diferencias más sobresalientes, se
encuentra en los niveles de acceso y la inclusión de funciones (métodos), como miembros.
La sintaxis para una definición típica de una clase es la siguiente:
class nombclase {
tipo var_miembro_priv_1;
tipo var_miembro_priv_2;
.
.
tipo var_miembro_priv_n;
public:
funcion_miembro_1;
funcion_miembro_2; Interface de la clase o el
. objeto
.
funcion_miembro_n;
}

17
Dependiendo, que la clase se cree con struct, union o class, tienen implícitamente, definidos niveles de acceso,
estos podrán ser cambiados explícitamente.
 Con struct los miembros son por defecto públicos
 Con class los miembros son por defecto privados.
 Con union los miembros son por defecto públicos, y no factibles de modificar explícitamente.
- 127 -
UNLaR - APUNTES DE PROGRAMACIÓN
Prof. Ing. Marcelo Daniel Camargo

Por ej. para definir las clase punto (en el plano)


class punto{
int x,y; // datos miembro privados de punto
public: // miembros publicos de punto
void poner(int,int); // Permite alterar coordenadas del punto
int getx(); // devuelve la absisa del punto
int gety(); // devuelve la ordenada del punto
};
Esta es una definición de punto que puede ser útil para un determinado fin, podría haber alternativas
que se ajusten mejor a otros fines.
Por ej. Definición de la clase angulo.
class angulo{
float v; // Angulo o arco en radianes
public:
float tomarvalor(); // Devuelve el valor del ángulo
void ponervalor(float v); // Actualiza valor del ángulo
float seno();
float coseno();
float tangente();};

La sintaxis para la declaración de un objeto, se lo hace de la misma forma que se declaraba una
variable del tipo estructura o uniones. Una declaración típica podría ser:
punto p,p1,p2,paux;
angulo a;
Asimismo, cuando se realiza un mensaje a un objeto (o se invoca a un método; o función miembro).
p.poner(3,4);
cout << “La absisa del punto es: ” << p.getX();
otro ej.
a.ponervalor(M_PI_2); // Constante definida en MATH.H que indica pi/2
cout << “El seno(pi/2)= ” << a.seno();
Una implementación válida del método seno de la clase angulo sería:
float angulo::seno(){
return sin(v);
}
Respecto a la implementación de las funciones miembros, se introduce un símbolo no utilizado hasta
el momento, el operador “::”, denominado operador de alcance. La forma de realizar la
implementación de la función miembro, se hace como en las funciones convencionales, solo
antecediéndole al nombre de la función, el nombre de la clase y el operador de alcance.
Por ej.
void punto::poner(int x, int y){ void punto::poner(int x, int y){

? 
x = x; punto::x = x;
y = y; punto::y = y;
} }

Obsérvese además, la utilidad que tiene el operador en la implementación de la derecha, para


resolver la ambigüedad de nombres, de variable de distintos ámbitos (x y y como miembros de la
clase punto y como parámetros de la función miembro punto::poner). En la implementación de la
izquierda, se están refiriendo únicamente los parámetros formales de la función, en lugar de hacer
lo que en realidad se pretende y que se resuelve con la implementación de la derecha.
Y mejor aun que la forma anterior es:
void punto::poner(int x, int y): punto::x(x), punto::y(y) {}
Y porque mejor?. Con esta modalidad le podemos dar valores a atributos constantes.

- 128 -
UNLaR - APUNTES DE PROGRAMACIÓN
Prof. Ing. Marcelo Daniel Camargo

Integrando los nuevos conceptos aprendidos.


/*************************************************************/
/* PUNTO - Definicion e implementacion de la clase punto */
/*************************************************************/
#include <iostream>

using namespace std;

class punto{
int x,y; // datos miembro privados de punto
public: // miembros publicos de punto
void poner(int,int); // Permite alterar coordenadas del punto
int getx(); // devuelve la absisa del punto
int gety(); // devuelve la ordenada del punto
};

int main(void){
punto p,q;
p.poner(0,0);
q.poner(100,100);
cout << "Valor absisa: " << p.getx() <<" ordenada: "<<p.gety()<< "\n";
p.poner(5,5);
cout << "Valor absisa: " << p.getx() <<" ordenada: "<<p.gety() <<endl;
}

void punto::poner(int x,int y){


punto::x=x;
punto::y=y;
}

int punto::getx(){
return x;
}

int punto::gety(){
return y;
}

La salida del programa es la siguiente:


Valor absisa: 0 ordenada: 0
Valor absisa: 5 ordenada: 5

/***********************************/
/* Implementacion de Clase ANGULO */
/***********************************/
#include <math.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
class angulo{
float v; // Angulo o arco en radianes
public:
float tomarvalor(); // Devuelve el valor del ángulo
void ponervalor(float v); // Actualiza valor del ángulo
float seno();
float coseno();
float tangente();
};
int main(){
angulo a;
- 129 -
UNLaR - APUNTES DE PROGRAMACIÓN
Prof. Ing. Marcelo Daniel Camargo

system("cls");
cout.precision(2);
a.ponervalor(M_PI_4); // Constante definida en MATH.H que indica pi/2
cout << " seno(1/4 pi)= " << a.seno() << "\n";
cout << " coseno(1/4 pi)= " << a.coseno() << "\n";
cout << "tangente(1/4 pi)= " << a.tangente() << "\n";
a.ponervalor(M_PI_2);
cout << " seno(1/2 pi)= " << a.seno() << "\n";
a.ponervalor(M_PI_2+M_PI_4);
cout << " seno(3/4 pi)= " << a.seno() << "\n";
a.ponervalor(M_PI);
cout << " coseno(pi)= " << a.coseno() << "\n";
return 0;
}

float angulo::tomarvalor(){
return v;
}

void angulo::ponervalor(float v){


angulo::v=v;
}

float angulo::seno(){
return sin(v);
}

float angulo::coseno(){
return cos(v);
}

float angulo::tangente(){
return tan(v);
}
La salida del programa es la siguiente:
seno(1/4 pi)= 0.71
coseno(1/4 pi)= 0.71
tangente(1/4 pi)= 1
seno(1/2 pi)= 1
seno(3/4 pi)= 0.71
coseno(pi)= -1

- 130 -
UNLaR - APUNTES DE PROGRAMACIÓN
Prof. Ing. Marcelo Daniel Camargo

Funciones inline
Esta característica incorporada al C++, permite declarar e implementar funciones que no utilizan el
mecanismo convencional de las funciones, el cual insume muchos recursos de espacio y tiempo,
sinó que se incorpora el código donde se lo invoca. Esto no pasa a nivel codigo fuente, sino es
resuelto en las siguientes etapas. Cabe aclarar, que este mecanismo se pude utilizar
independientemente de las clases o de la programación OO. Cuando se abordó el tema funciones,
se analizaron las conveniencias de convertir un segmento de código en función, como así también
se analizaron la implementación de funciones vs. las macros. Si el procedimiento es relativamente
grande o poco invocado, se justifica la implementación convencional de una función. En C++, cuando
se implementan funciones, muy invocadas y/o de poco código, existe una alternativa a las macros,
que evita los tiempos de invocación y salida de una función. Esta alternativa, son las funciones inline.
Esto es aplicable también a las funciones miembros de una clase. Todas las funciones miembros,
que se han visto hasta el momento, son candidatas para ser inline, ya que son de una o dos líneas
de código, provocando que mejore la performance global del programa.
Se define una función en línea precediendo a la definición de la función, la palabra reservada inline.
Por ejemplo, en la clase angulo se implementó la función miembro valor. Para que esta sea
declarada “en línea”, la sintaxis debe ser:
inline float angulo::valor()
{return v;}
en el caso de las funciones miembros de una clase, existe una alternativa, para la definición inline
aún más simple que la mencionada. Es colocando el código de la función en la declaración de la
clase, sin necesidad de la palabra reservada inline. Como ejemplo reutilizaremos la clase ángulo.
class angulo{
float v; // Angulo o arco en radianes
public:
float valor(){return v;}
void ponervalor(float valor){v=valor;}
float seno() {return sin(v);}
float coseno() {return cos(v);}
float tangente() {return tan(v);}
};

Constructores
Es un mecanismo que implementa C++, para inicializar objetos. Son funciones miembros especiales,
que no tienen tipo devuelto y pueden o no tener parámetros, en las que se indican todas las
acciones necesarias para que el objeto sea inicializado. El nombre que lleva esta funcion miembro
es el mismo de la clase.
El constructor se autoinvoca, cuando se declara un objeto estático o cuando se crea un objeto
dinámico (El concepto de objeto dinámico lo veremos más adelante).
Los ejemplos que hemos visto hasta el momento, requerirían implementaciones muy simples como
la que sigue en la clase punto:
punto::punto(){
x=0; y=0;
}

Constructor por defecto


Es el caso en el que el constructor no se le indican argumentos en su declaración, como en el
ejemplo previo. Una declaración más adecuada del constructor anterior, que lograría idéntico efecto,
es a traves de inicializadores de miembros datos (solo válido para constructores), como se ve a
continuación.
punto(): x(0), y(0){}

- 131 -
UNLaR - APUNTES DE PROGRAMACIÓN
Prof. Ing. Marcelo Daniel Camargo

Constructor parametrizado
Es el constructor tiene parámetros. Por ej.
punto::punto(int vx, int vy){
x= vx;
y= vy;
}
Esto permite en el momento de la declaración inicializar los miembros datos de la clase, utilizando
los argumentos de la invocación. Por ej.
punto p(1,1);
A esta forma de definir el constructor se le llama Constructor general, en el cual se les da el valor
de los argumentos del constructor, a todos los miembros datos del objeto. De la misma manera
que en el caso del constructor por defecto, la forma adecuada de implementarlo inline es la siguiente:
punto(int vx, int vy): x(vx), y(vy){}

Constructor de copia
Cuando es necesario crear objetos a partir de otros existente, se lo puede hacer a través de este
mecanismo. El constructor tiene un único argumento, la referencia constante al objeto de su misma
clase:
punto(const punto &p)
{ x= p.x;
y= p.y;
}
y análogamente a los ejemplos anteriores:
punto(const punto &p) : x(p.x), y(p.y) {}
Entonces dado algún objeto punto declarado, por ejemplo:
punto p1(10,20);
el constructor de copia se autoinvocaría en las siguientes declaraciones:
punto p2 = p1; // Declarar p2 y hacerlo igual a p1
o lo que es lo mismo:
punto p2(p1);
si el constructor de copia no es declarado, se crea implícitamente uno por defecto, que hace
exactamente lo que hicimos anteriormente, si no fuera necesario redefinir de alguna manera esa
lógica, no habría necesidad de declarar el constructor de copia.

Destructores
El destructor es quien cumple la actividad complementaria del constructor, finalizando o dandole un
cierre a las actividades comenzadas por el constructor.
Este a diferencia del constructor, nunca tendrá argumentos. Se autoinvoca, en el caso de los
objetos estáticos cuando se abandona el ambito en el cual fue declarado.
La implementación de un destructor de la clase punto, debería ser:
~punto()
El destructor toma sentido cuando se debe realizar una o más operaciones, cuando es eliminado el
objeto. Por ejemplo, eliminar asignaciones dinámicas de memoria o cerrar archivos.

- 132 -
UNLaR - APUNTES DE PROGRAMACIÓN
Prof. Ing. Marcelo Daniel Camargo

Asignación dinámica de memoria en C++


El new es similar en su finalidad a malloc, pero este es un operador unario del C++, no una función
como en el C. Así también el delete (operación inversa del new), de modo que por formar parte del
lenguaje no se necesitan incluir cabeceras para utilizarlos.
Sintaxis:
<puntero> = new <tipo> [ long_arreglo ] ( valor_inicial )
Ej.
//AsigDinMem
#include <iostream>
#include <string.h>
using namespace std;
int main()
{char *s= new char[9]; // Declara s como puntero a char
// Reserva espacio para 9 char y lo apunta con s
strcpy(s,"Prueba: ");
cout << s;
int *i= new int (10); // Reserva espacio para 1 int y lo apunta con i
// inicializa el entero en 10.
int *j= new int[2]; // Reserva espacio para 2 int y lo apunta con j
j[0]=20; j[1]=30; // Asigna valores a los elementos del arreglo
cout << *i << " " << j[0] << " " << j[1];
}
En pantalla veremos:

Prueba: 10 20 30

Otro ejemplo, solicitando la cantidad de elementos del arreglo en tiempo de ejecución:


cin >> n;
s = new char[n];
Al igual que con malloc, si no hay memoria disponible, la operación new devuelve 0, es decir, el valor
nulo (null).
Como ya se mencionó, la operación delete es la inversa o complemento de la función new. Esta
elimina la asignación de memoria solicitada mediante new.
Sintaxis:
delete[] <puntero>
Ej.:
delete[] s; //Corchetes indican que destruye area de memoria y no objeto

- 133 -
UNLaR - APUNTES DE PROGRAMACIÓN
Prof. Ing. Marcelo Daniel Camargo

En el siguiente ejemplo se crea una clase curso, que tiene los siguientes atributos

curso
-nombmat: char* = NULL
-alumnos: char*[]
-calu:int=0 Este diagrama responde a la
+curso(const char *) representación que se hace de las
+cantalu(): int clases en UML
+materia(void): char *
+agregar_alumno(const char *): void
+alumno(int): char *
18

El código de esta clase es el siguiente:


class curso
{ char *nombmat; // Nombre de la materia
char *alumnos[maxalumnos]; // Arreglo de nombres de alumnos
int calu; // Contador de alumnos
public:
curso(const char *); // el constructor
int cantalu() {return calu;} // Cant.de alumnos ingresados
char *materia(void) {return nombmat;} // Devuelve nombre materia
void agregar_alumno(const char *); // Agrega un alumno al curso
char *alumno(int orden) {return alumnos[orden];} // devuelve alumno
};

/********************************************/
/* CURSO: Definicion de la clase <curso> */
/********************************************/
#include <string.h>
#include <stdlib.h>
#include <conio.h>
#include <iostream>
#define maxalumnos 100
using namespace std;
class curso
{ char *nombmat; // Nombre de la materia
char *alumnos[maxalumnos]; // Arreglo de nombres de alumnos
int calu; // Contador de alumnos
public:
curso(const char *);// el constructor
int cantalu() {return calu;} // Cantidad de alumnos ingresados
char *materia(void) {return nombmat;} // Devuelve nombre materia
void agregar_alumno(const char *); // Agrega un alumno al curso
char *alumno(int orden) {return alumnos[orden];} // devuelve alumno
};
int main()
{ curso pr("Programacion I"),pd("Procesamiento de datos I");// Declara de

18
Visibilidad se aplica a los componentes de un diagrama de clases.

 Publica. Los elementos son accesibles desde cualquier clase de cualquier paquete. Se señalizan con un signo más [ + ] o un icono
característico.
 Paquete. En Java los elementos son visibles desde cualquier clase del mismo paquete. Se señalizan con un signo tilde [ ~ ] o un icono
característico.
 Protegida. Los elementos con este alcance son visibles únicamente dentro de la clase y desde las clases descendientes de ella. Se señalizan
con un signo numeral [ # ] .
 Privada. Los elementos marcados son visibles únicamente dentro de la clase a la que pertenecen. Se señalizan con un signo menos [ - ] o
un icono característico.

- 134 -
UNLaR - APUNTES DE PROGRAMACIÓN
Prof. Ing. Marcelo Daniel Camargo

objetos
// Asignaciones
pr.agregar_alumno("AREVALO, JORGE ALFREDO");
pr.agregar_alumno("ARIQUE, FEDERICO");
pr.agregar_alumno("BALBUENA, ARIEL");
pr.agregar_alumno("CASEROS, ALDO JULIAN");

pd.agregar_alumno("AYAN, ALBERTO");
pd.agregar_alumno("ALBRIEU GUZMAN, CARLOS");
pd.agregar_alumno("ARIKA, LUIS ESTEBAN");
// Impresion
system("cls");
cout << "MATERIA: "<< pr.materia() <<
" - Cant. Alumnos: " << pr.cantalu()<<"\n";
int i;
for (i = 0; i<pr.cantalu(); ++i)
cout << (i+1) << ": " << pr.alumno(i) << "\n";

cout << "\nMATERIA: "<< pd.materia() <<


" - Cant. Alumnos: " << pd.cantalu()<<"\n";
for (i = 0; i<pd.cantalu(); ++i)
cout << (i+1) << ": " << pd.alumno(i) << "\n";
return 0;
}

curso::curso(const char *s)


{ nombmat = new char[strlen(s)+1];// Crea string dinam. y lo apunta
strcpy(nombmat,s); // Le asigna parametro
calu = 0; // Inicializa contador
}

void curso::agregar_alumno(const char *s)


{ if (calu < maxalumnos)
{alumnos[calu] = new char[strlen(s)+1]; // Crea string dinam.
strcpy(alumnos[calu++],s); // Le asigna param. e incr. contador
}
}

La salida de este programa será:


MATERIA: Programación I - Cant. Alumnos: 4
1: AREVALO, JORGE ALFREDO
2: ARIQUE, FEDERICO
3: BALBUENA, ARIEL
4: CASEROS, ALDO JULIAN
MATERIA: Procesamiento de datos I - Cant.
Alumnos: 3
1: AYAN, ALBERTO
2: ALBRIEU GUZMAN, CARLOS
3: ARIKA, LUIS ESTEBAN

- 135 -
UNLaR - APUNTES DE PROGRAMACIÓN
Prof. Ing. Marcelo Daniel Camargo

Objetos Dinámicos
Una característica que distingue al new y al delete respecto del malloc y el free, es la construcción
y destrucción de objetos, con las actividades asociadas a estos, es decir, ante la asignación dinámica
de memoria a un objeto se dispara el constructor y viceversa con el destructor.
A continuación se muestra un ejemplo, en el cual se aplica el operador new. En este revisaremos
varios de los conceptos vistos. En el se define la clase Cstring. Además se definen las funciones
miembro que permiten el acceso a los datos.
En el siguiente ejemplo se pretende comprobar, la autoinvocación del constructor y el destructor, en
el momento de la declaración del objeto.

/*******************************************************
* NewObjeto - Creacion dinamica de objetos e *
* invocacion implicita del constructor y el destructor *
********************************************************/
#include <iostream>
#include <string.h>
using namespace std;

class CString{
char str[30];
public:
CString();
~CString(){cout << "Objeto destruido";}
char *getStr() {return str;}
};

int main(){
CString *p; // declaro puntero a CStrig
p= new CString; // creo objeto p dinámicamente, se llama al aconstructor
delete p; // elimino el objeto dinam. Se llama al destructor
return 0;
}

CString::CString(){
strcpy(str,"Cadena inicializada\n");
cout << str << "Objeto Construido\n\n";
}

Como salida del pequeño ej., se mostrará la cadena inicializada por el constructor.

Cadena inicializada
Objeto Construido
Objeto destruido

Los objetos por sí solos, no son los que dotan de potencia al C++, sino el mecanismo de herencia,
que permite que sea más fácil el mantenimiento del código desarrollado, y su futura reutilización en
nuevas aplicaciones.

- 136 -
UNLaR - APUNTES DE PROGRAMACIÓN
Prof. Ing. Marcelo Daniel Camargo

Funciones Amigas (Friends)


En principio, los miembros privados y protegidos de una clase no pueden ser accedidos desde
fuera de la clase en la que se declararon. Sin embargo, esta regla no afecta a las funciones
amigas. Las funciones amigas son declaradas con la palabra reservada friend. Si se declara una
función externa amiga, a esta se le permitirá tener acceso a los miembros privados19 y protegidos
de esta clase; esto se hace al declarar el prototipo de esta función externa dentro de la clase,
antecedida por la palabra reservada friend20.

#include <iostream>
using namespace std;

class CRectangulo{
int ancho, alto;
public:
void set_val (int, int);
int superficie() {return (ancho * alto);}
friend void duplicar(CRectangulo&); // Funcion amiga, no miembro
};

int main (){


CRectangulo rect;
rect.set_val(2,3);
cout << rect.superficie() << " ";
duplicar(rect);
cout << rect.superficie();
return 0;
}

void CRectangulo::set_val(int a, int b) {


ancho = a;
alto = b;
}

// Funcion amiga de CRectangulo, observe sin clase ni op. de ámbito


void duplicar(CRectangulo &rectan){
rectan.ancho*=2;
rectan.alto *=2;
}
La salida es la superficie de un rectangulo de 4 x 6
6 24
Nos podemos valer de este mecanismo para implementar la “adaptación” (sobrecarga - que veremos
en detalle más adelante) del operador de salida “<<” para que permita la salida por pantalla del
objeto. Para ello, en el caso de la clase punto debemos declarar dentro de la clase:
friend ostream& operator << (ostream& co, const punto &a);
e implementer la función amiga:
ostream & operator << (ostream& co, const punto &a){
co << "(" << a.x << "," << a.y << ")"; // (a.x,a.y)
return co;
}
A partir de esto podemos mostrar dos puntos p y q operándolos con cout <<, como sigue:
cout << p << q;

19
"C++: Donde los amigos tienen acceso a tus miembros privados" -- Gavin Russell Baker
20
Una función amiga puede declararse en cualquier sección de la clase y no se ve afectada por los modificadores private
y public, debido a que no es miembro de la clase.
- 137 -
UNLaR - APUNTES DE PROGRAMACIÓN
Prof. Ing. Marcelo Daniel Camargo

Clases Amigas
Así como se puede definir una función amiga, también se puede definir una clase amiga,
concediendo a la primera clase el acceso a los miembros protegidos y privados de la segunda.

#include <iostream>
using namespace std;

class Rectangulo; //Declaracion anticipada (forward) de Rectángulo

class Cuadrado{
private:
int lado;
public:
void setlado (int a){lado=a;}
friend class Rectangulo; // permito que los metodos de Rectangulo
}; // use miembros de Cuadrado
class Rectangulo{
int ancho, alto;
public:
int superficie (){return (ancho * alto);}
void convertir(Cuadrado cua){ancho = cua.lado;alto = cua.lado;}
}; //convertir accede a la parte privada
//de Cuadrado (Cuadrado::lado).
int main (){
Cuadrado cuad;
Rectangulo rect;
cuad.setlado(4);
rect.convertir(cuad);
cout << rect.superficie();
return 0;
}

En este ejemplo, hemos declarado Rectangulo como amiga de Cuadrado para que las funciones
miembro Rectangulo pueden tener acceso a los miembros protegidos y privados de Cuadrado y
más concretamente a Cuadrado::lado.
También se ve algo nuevo al comienzo del programa, una declaración vacía de la clase Cuadrado.
Esto es necesario, porque dentro de la declaración de Rectangulo nos referimos a Cuadrado (como
un parámetro de convertir()). La definición de Cuadrado se hace más adelante, así que si no
incluimos una declaración vacía previa de Cuadrado esta clase no sería visible en la definición de
Rectangulo. Se debe considerar que las amistades no son conmutativas. En el ejemplo,
Rectangulo se considera como clase amiga de Cuadrado, pero Rectangulo no considera amiga
Cuadrado, por lo tanto Cuadrado no puede acceder a los miembros privados y protegidos de
Rectangulo. Si así se deseara, se puede además declarar a Cuadrado como amigo Rectangulo.
Otra propiedad de las amistades es la no transitividad: el amigo de un amigo, no es considerado
como amigo, a menos que se especifique de forma explícita.

- 138 -
UNLaR - APUNTES DE PROGRAMACIÓN
Prof. Ing. Marcelo Daniel Camargo

Herencia (Generalización)
Herencia es la capacidad de un objeto (clase) para utilizar los atributos y los métodos existentes en
clases antepasadas o ascendientes. Esta permite la reutilización de código desarrollado
anteriormente.
Cuando una clase toma características o hereda de una clase de nivel superior se dice que la clase
inferior deriva de la clase superior. La flecha y su sentido indica “deriva de”.
Mediante el mecanismo de herencia una clase puede aumentar su especialización, en clases de
niveles o jerarquías inferiores. Y asimismo, clases que comparten ciertas carácterísticas, pueden
dar lugar a una nueva clase de jerarquia superior que concentre las características comunes, a
esto se le llama generalización. Algunos autores y software de diseño de diagramas de clase UML
hacen referencia a la herencia como generalización.
Una clase puede tener subclases. Por ejemplo, la clase persona puede tener las subclases
estudiante y empleado. A su vez, la clase estudiante puede tener como subclases a los de pregrado,
grado y postgrado, mientras que la clase empleado puede tener como subclases al administrativo y
al de mantenimiento. De este modo es factible crear diversas jerarquías de tipos, dependiendo del
problema a analizar.
Persona

Estudiante Empleado

Pregrado Grado Posgrado Administrativo Mantenimiento

Una subclase hereda los datos y los métodos, de su superclase. También puede agregar sus datos
y métodos específicos.
Cuando una subclase incluye un atributo extra, éste no afectará a la clase superior. Por otro lado,
es común que en una clase que constituye una especialización, desee modificar alguno de los
métodos heredados, para adecuar su respuesta a algún mensaje.

Tipos de herencia
Herencia simple
Un tipo derivado se crea a partir de una única clase base.

Figura
El triángulo es derivado de
figura, únicamente.
Triángulo Rectángulo

Herencia múltiple
Una clase tienen más de una ascendiente Inmediato.

Alumno Graduado

Alumno de Postgrado es derivado


Alumno de de Graduado y de Alumno
Postgrado

- 139 -
UNLaR - APUNTES DE PROGRAMACIÓN
Prof. Ing. Marcelo Daniel Camargo

Herencia en C++
En C++, la herencia se maneja por medio de la derivación de clases.
La derivación de clases en C++ se rige por la siguiente sintaxis:

class <clase_derivada> : [public|private] <clase_base1>


[,[public|private] <clase_base2>] {
};
Si no se especifica ninguno de los dos (public o private), por defecto se asume que es private.
public: los miembros heredados de la clase base conservan el tipo de acceso con que fueron
declarados en ella.
private: todos los miembros heredados de la clase base pasan a ser miembros privados en la
clase derivada.

Metodos virtuales
Los métodos o funciones miembros virtuales en C++ son una solución que brinda el lenguaje para
redefinir métodos heredados de clases padres. Esto es lo que permite aplicar un mismo método
en objetos polimórficos. Dicho de otra manera, los métodos virtuales permiten que clases
derivadas de una misma base (clases hermanas) puedan tener diferentes versiones de un método.
Se utiliza la palabra reservada virtual para avisar al compilador que este método será polimórfico y
que en las clases derivadas existen distintas definiciones de el.
Sintaxis:
virtual tipo nom_func() {Implementación inline;} //
La declaración de virtual en un método de una clase, implica que esta es polimórfica, y que no se
utilizará directamente para instanciar objetos, sino como superclase de una jerarquía.
La posibilidad que un mismo método puede exhibir distintos comportamientos en los descendientes
de una base común, es precisamente lo que posibilita y define el polimorfismo. En estos casos se
dice que las funciones de clases descendientes se sobrescriben21 ("override") la función virtual de
la superclase, pero esta versión de la superclase puede no existir en absoluto. Es probable que en
ella solo exista una declaración del tipo virtual, sin que exista una definición explícita de la misma.
Por ejemplo, una clase vehículo podría tener las clases virtuales lavar, estacionar o manejar, y de
esta clase podrían heredar las clases automóvil, moto y bicicleta, las implementaciones de estos
métodos variarán en su lógica para cada tipo de vehículo.

# include <iostream>
using namespace std;
class Figura {// No es abstracta porque superficie está implementada
protected:
int ancho, alto;
public:
void setval ( int a, int b){ancho = a, alto = b;}
virtual int superficie() {return 0;}
};

class Rectangulo: public Figura {


public:
int superficie(){return (ancho * alto);}
};

class Triangulo: public Figura {


public:
int superficie (){ return (ancho * alto / 2);}

21
Se pueden encontrar como traducciones de override a sustituir o reemplazar, aunque se popularizó en castellano
sobreescribir en el contexto de la POO.
- 140 -
UNLaR - APUNTES DE PROGRAMACIÓN
Prof. Ing. Marcelo Daniel Camargo

};

int main () {
Rectangulo rect; // Se crea un rectangulo
Triangulo trgl; // Se crea un triangulo
Figura poli; // Instanciacion de Figura
Figura* poli1 = &rect;
Figura* poli2 = &trgl;
Figura* poli3 = &poli;
poli1-> setval(4,5);
poli2-> setval(4,5);
poli3-> setval(4,5);
cout << poli1-> superficie() << endl; // Salida 20
cout << poli2-> superficie() << endl; // Salida 10
cout << poli3-> superficie() << endl; // Salida 0
return 0;
}

- 141 -
UNLaR - APUNTES DE PROGRAMACIÓN
Prof. Ing. Marcelo Daniel Camargo

Clase abstracta (casi Interfaz o Interface)


Esta cararacterística, permite describir el comportamiento o las capacidades de la clase C ++ sin
comprometer la implementación particular.
Las clases abstractas del C ++ (en otros lenguajes interfaces) no deben confundirse con la
abstracción de datos, que es un concepto de mantener los detalles de implementación separados
de datos asociados.
Una clase abstracta se hace declarando al menos una de sus funciones como función virtual
pura. Una función virtual pura se especifica mediante la colocación de "= 0" en su declaración de la
siguiente forma:
virtual tipo NombreFunVirtualPura() = 0;
Estas clases no pueden ser instanciadas. El propósito de una clase abstracta es proporcionar la
definición común de una clase base que compartirán sus clases derivadas.
A las clases se las identifica como abstractas si definen métodos abstractos. En el último ejemplo,
si en lugar de hacer una implementación vacia de superficie en Figura la terminamos con "= 0;",
de la siguiente manera:
virtual int superficie() = 0;
superficie pasa a ser una funcion miembro virtual pura (o método abstracto), y Figura pasa a
ser una clase abstracta no pudiendo instanciarse. Si se prendiera instanciarla, la compilación
reportará el error “No puede declarar esta variable, por ser de tipo abstracto”

Probar con el ejemplo anterior haciendo a superficie una funcion virtual pura y a la clase abstracta.

# include <iostream>
using namespace std;
class Figura{ // Es una clase abstracta porque superficie no está
implementada
protected:
int ancho, alto;
public:
void setval ( int a, int b){ancho = a, alto = b;}
virtual int superficie() =0; // función miembro virtual pura
}; // o método abstracto
class Rectangulo: public Figura {
public:
int superficie(){return (ancho * alto);}
};

class Triangulo: public Figura {


public:
int superficie (){ return (ancho * alto / 2);}
};

int main () {
Rectangulo rect; // Se crea un rectangulo
Triangulo trgl; // Se crea un triangulo
Figura poli; // Instanciacion de Figura
Figura* poli1 = &rect;
Figura* poli2 = &trgl;
Figura* poli3 = &poli;
poli1-> setval(4,5);
poli2-> setval(4,5);
poli3-> setval(4,5);
cout << poli1-> superficie() << endl; // Salida 20
cout << poli2-> superficie() << endl; // Salida 10
cout << poli3-> superficie() << endl;
return 0;
}

- 142 -
UNLaR - APUNTES DE PROGRAMACIÓN
Prof. Ing. Marcelo Daniel Camargo

Accesibilidad a los miembros de la clase base


La accesibilidad de los miembros de la clase heredera variará, de acuerdo a lo que se observa en la
sig. tabla:

el acceso a la función
Si en clase base y el modif. de acceso
miembro de la clase base
el miembro es: de la clase deriv. es:
desde la clase derivada es:
Private Private inaccesible
Protected Private private
Public Private private
Private public inaccesible
Protected public protected
Public public public

En el siguiente esquema, sintetiza el contenido de la tabla anterior.

Modificadores de acceso de
TEGI D miembros de la clase base
RO
P

Modificadores de acceso de
la clase derivada
P RO TEGID O
PU BLIC O
INACCESIBLE
PR IVAD O

acceso a la función miembro


de la clase base desde la
clase derivada

Cuando se utiliza la palabra class, el modificador de acceso está predefinido como private; cuando
se utiliza la palabra struct, está predefinido como public.

- 143 -
UNLaR - APUNTES DE PROGRAMACIÓN
Prof. Ing. Marcelo Daniel Camargo

En el siguiente ej. se ven algunos de los conceptos vistos hasta ahora.

#include <iostream>
#include <stdlib.h>
using namespace std;

class punto{
float x,y;
public:
punto(float vx,float vy){x=vx;y=vy;}
void setpunto(float vx,float vy){x=vx;y=vy;}
float getx(){return x;}
float gety(){return y;}
};

class circulo:public punto{


float radio;
public:
circulo(float x,float y,float r);
void setradio(float r){radio= r;}
float getradio(){return radio;}
void mostrar();
};

int main()
{ system("cls");
circulo c(1.2,3.4,5.6);
cout << "Salida: ";
c.mostrar();
c.setpunto(2,6);
c.setradio(10);
c.mostrar();
return 0;
}

circulo::circulo(float vx,float vy,float r):punto(vx,vy){


radio=r;
}

void circulo::mostrar(){
cout << getx() << " " << gety() << " " << radio << "\n";
}

Salida:
1.2 3.4 5.6
2 6 10

- 144 -
UNLaR - APUNTES DE PROGRAMACIÓN
Prof. Ing. Marcelo Daniel Camargo

Otras relaciones entre objetos


Además de la relación de herencia, los objetos pueden estar conectados a través de otros tipos de
relaciones. Estas relaciones pueden ser:
 Persistentes: Se establecen si la comunicación entre objetos se registra de algún modo, y
por lo tanto puede ser utilizada en cualquier momento.
 No persistentes: El vínculo entre objetos desaparece luego de ser empleado.
En cualquier caso, en la mayor parte de los casos la resolución de un problema más o menos
complejo exige la colaboración entre objetos. Esta colaboración se puede llevar a cabo mediante el
establecimiento de relaciones.
 entre clases (relación de herencia/ generalización)
 entre instancias/objetos (relación todo-parte: agregación y composición y la relación
asociación).
Relación todo-parte (agregación y composición)
En este tipo de relación una instancia forma parte de otra. Se dice que A está compuesto de B o
que A tiene B. La diferencia entre la asociación y la relación todo-parte radica en la asimetría de
toda relación todo-parte. En teoría se distingue entre dos tipos de relación todo-parte:
a) Agregación () (por referencia). Se basa en la idea de observar o entender un objeto como
composición de otros objetos. Se entenderán como relaciones en las cuales una o más clases
aparecen como atributos de otra clase. El "todo" está representado por la clase que abarca a las
otras clases, y las "partes" están dadas por las diversas clases incorporadas. La mejor forma de
identificar a la agregación es preguntarse si la clase que queremos definir "tiene un" (en inglés, "has
- a") atributo de la otra clase.
Ejemplo: un equipo y sus miembros.
b) Composición () (por valor) es un tipo particular de agregación, (o también llamada agregación
fuerte), en la cual los objetos agregados no tienen sentido fuera del objeto resultante. También
se puede entender la composición como una relación en la que, los objetos agregados dejan de
existir cuando lo hace el objeto compuesto (o contenedor).
Por ejemplo: un rectángulo tiene cuatro vértices, un comercio está organizado tiene un conjunto de
secciones de venta, etc. Cabe destacar, que es una composición cuando la relación se conforma en
una inclusión por valor (lo que implica que un componente está como mucho en un compuesto, pero
no impide que haya objetos componentes no relacionados con ningún compuesto). En este caso si
se destruye el compuesto se destruyen sus componentes. Por ejemplo: un ser humano y sus
miembros.
Es importante aclarar, que algunas relaciones pueden ser consideradas agregaciones o
composiciones, dependiendo del contexto en que se utilicen.

Composición
ordenado Punto
3..* 1
Círculo
Polígono
Radio
* *
Estilo

Color Agregación
1 Relleno 1
Aregación y composición
Como se lee esta grafica:
 Un polígono tiene o se compone de 3 o más vértices que requieren su ubicación en el plano.
 Asimismo, tiene un estilo que puede ser compartido por más de un poligono.
- 145 -
UNLaR - APUNTES DE PROGRAMACIÓN
Prof. Ing. Marcelo Daniel Camargo

c) Asociación ( dirigida) dos instancias A y B están asociadas, sí previo a la relación existían ambas,
en forma independiente. La creación o desaparición de una de ellas no implica la creación o
destrucción de la otra.
Las relaciones de asociación son más débiles que las relaciones de agregación, en el sentido de
que no requieren crear un objeto nuevo a partir de otros objetos, sino únicamente que los objetos
interactúen entre sí.
Las relaciones de asociación crean enlaces entre objetos. Estos enlaces no tienen por qué ser
permanentes.
Un ejemplo clásico de relación de asociación es la relación "empresa -empleado". Podemos definir
una clase "Empresa" y una clase "Empleado" que nos permitan representar esta relación:

La asociación expresa una relación (uni o bidireccional) entre las instancias de clases conectadas.
El sentido en que se recorre la asociación se denomina direccionalidad o navegabilidad de la
asociación (puede ser unidireccional o bidireccional). Cada extremo de la asociación se
caracteriza por el rol o papel que juega cada objeto situado en cada extremo de dicha relación. La
cardinalidad o multiplicidad es el número mínimo y máximo de instancias que pueden relacionarse
con la otra instancia del extremo opuesto de la relación. Por defecto es 1. El formato en el que se
especifica es (mínima..máxima) o (mínima, máxima).
1 Uno y sólo uno (por defecto) Un auto tiene un motor.
1..* Uno a muchos (al menos uno) Un auto tiene muchas autopartes.
*..* Muchos a muchos Un auto puede tener muchos dueños o un
dueño puede tener muchos autos.

/*Herencia y entorno grafico

[Ubicacion]
^
|
[Punto]
^
|
[Circulo]
*/
#include <winbgim.h>
// En Proyect/Build Options/Linker Settings/Other linker options
// Pegar: -lbgi -lgdi32 -lcomdlg32 -luuid -loleaut32 -lole32
#include <iostream>
#include <stdio.h>
#define ESC 27
#define ARR 75
#define ABA 77
#define IZQ 72
#define DER 80
#define PGUP 73
#define PGDN 71

using namespace std;


class Ubicacion {
int X,Y;
public:
Ubicacion(int X, int Y) {
Ubicacion::X = X;
Ubicacion::Y = Y;
cout<<"Ubicacion::Ubicacion("<<X<<','<<Y<<')'<<endl;
}

int GetX() {
return X;

- 146 -
UNLaR - APUNTES DE PROGRAMACIÓN
Prof. Ing. Marcelo Daniel Camargo

cout<<"Ubicacion::GetX"<<endl;
}
int GetY() {
return Y;
cout<<"Ubicacion::GetY"<<endl;
}
void SetX(int X) {
Ubicacion::X= X;
cout<<"Ubicacion::SetX("<<X<<')'<<endl;
}
void SetY(int Y) {
Ubicacion::Y= Y;
cout<<"Ubicacion::SetY("<<Y<<')'<<endl;
}
};

class Punto : public Ubicacion { // derivacion publica de la clase


Ubicacion;
boolean Visible; // Las clases que se deriven de Punto podran
acceder
public:
Punto(int InitX, int InitY, boolean
Visible):Ubicacion(InitX,InitY) {

cout<<"Punto::Punto("<<InitX<<','<<InitY<<','<<Visible<<')'<<endl;
if (Visible) {
Punto::Visible = true;
Ver();
}
else {
Punto::Visible= false;
Ocultar();
}
}
boolean GetVisible() {
return Visible;
}
void SetVisible(boolean Visible) {
Punto::Visible= Visible;
cout<<"Punto::SetVisible("<<Visible<<')'<<endl;
}
void Ver();
void Ocultar();
void Mover(int NewX, int NewY);
};

class Circulo : public Punto { // derivacion privada de la clase Punto;


// y por su intermedio de la clase ubicacion
int Radio;
boolean Visible;
public:
Circulo(int InitX, int InitY, int Radio, boolean
Visible):Punto(InitX,InitY,false) {

cout<<"Circulo::Circulo("<<InitX<<','<<InitY<<','<<Radio<<','<<Visible<<
')'<<endl;
SetRadio(Radio);
if (Visible) {
Circulo::Visible = true;
Ver();
}
else Circulo::Visible= false;
- 147 -
UNLaR - APUNTES DE PROGRAMACIÓN
Prof. Ing. Marcelo Daniel Camargo

}
int GetRadio() {
return Radio;
}
void SetRadio(int Radio) {
Circulo::Radio= Radio;
}
void Ver(void);
void Ocultar(void);
void Expandir(int);
void Contraer(int);
void Mover(int, int);
};

void Punto::Ver(void) {
Visible = true;
putpixel(GetX(), GetY(), getcolor()); // utiliza el color por
defecto
cout<<"Punto::Ver"<<endl;
};

void Punto::Ocultar(void) {
Visible = false;
cout<<"Punto::Ocultar"<<endl;
putpixel(GetX(), GetY(), getbkcolor()); // utiliza el color de fondo
para borrar
};

void Punto::Mover(int X, int Y) {


cout<<"Punto::Mover("<<X<<','<<Y<<')'<<endl;
if (Visible)
putpixel(GetX(), GetY(), getbkcolor());// solo apagarlo sin
cambiar su estado
SetX(X); // Cambiar las coordenadas X y Y a una nueva Ubicacion
SetY(Y);
if (Visible) Ver(); // mostrar el punto en la nueva Ubicacion
};

void Circulo::Ver(void) {
cout<<"Circulo::Ver"<<endl;
Visible = true;
if (Punto::GetVisible()) Punto::Ver();
circle(GetX(),GetY(), GetRadio()); // Graficar el Circulo
}

void Circulo::Ocultar(void) {
cout<<"Circulo::Ocultar"<<endl;
unsigned int TempColor;
TempColor = getcolor(); // salvar el color actual
setcolor(getbkcolor()); // configurar el color de fondo
Visible = false;
circle(GetX(), GetY(), Radio); // borrar circulo
setcolor(TempColor); // devolver el color de graficacion
};

void Circulo::Expandir(int n) {
cout<<"Circulo::Expandir"<<endl;
Ocultar(); // borrar el circulo anterior
Radio += n;
Ver(); // Dibujar el nuevo circulo
};

- 148 -
UNLaR - APUNTES DE PROGRAMACIÓN
Prof. Ing. Marcelo Daniel Camargo

void Circulo::Contraer(int n) {
cout<<"Circulo::Expandir"<<endl;
Ocultar(); // borrar el circulo anterior
if (Radio > 0) Radio -= n; // expandir el radio evitando que se
negativice
Ver(); // Dibujar el nuevo circulo
};

void Circulo::Mover(int NuevaX, int NuevaY) {


cout<<"Circulo::Mover"<<endl;
Ocultar(); // borrar el Circulo anterior

if (Punto::GetVisible()) putpixel(GetX(), GetY(), getbkcolor()); //


solo apagarlo sin cambiar su estado
SetX(NuevaX); // Dar la nueva Ubicacion
SetY(NuevaY);
if (Visible) Ver();
Ver(); // Graficar en la nueva Ubicacion
};

void VerUbicacionEnXY(int x,int y) { // Transforma los dos enteros en


string
// y los muestra en X,Y del entorno graf.
cout<<"VerUbicacionEnXY <----No es miembro"<<endl;
char s1[15]="(",s2[6];
sprintf(s2, "%d", x);
strcat(s1,s2);
strcat(s1,", ");
sprintf(s2, "%d", y);
strcat(s1,s2);
strcat(s1,")");
outtextxy(x-40,y+5,s1);
}

int main() {
initwindow(800,600);
Punto P(100,100,true);
getch();
cout<<endl;

P.Mover(150,100);
getch();
cout<<endl;

P.Mover(200,100);
getch();
cout<<endl;

P.Ocultar();
getch();
cout<<endl;

P.Ver();
getch();
cout<<endl;

Circulo C(300,300,100,true);
getch();
cout<<endl;

C.Contraer(10);
getch();
- 149 -
UNLaR - APUNTES DE PROGRAMACIÓN
Prof. Ing. Marcelo Daniel Camargo

cout<<endl;

C.Mover(C.GetX(),C.GetY()+85);
getch();
cout<<endl;

C.Mover(C.GetX(),C.GetY()+92);
getch();
cout<<endl;

C.Punto::Ver();
getch();
cout<<endl;
VerUbicacionEnXY(C.GetX(),C.GetY());
getch();
cleardevice();

C.Ver();
bool seguir = true;
while (seguir) {
int ch = getch();
switch (ch) {
case ESC:
seguir = false;
break;
case '+':
C.Expandir(3);
break;
case '-':
C.Contraer(3);
break;
case 0:// Teclas especiales de doble codigo con 224
ch = getch();
switch (ch) {
case 71:
cout <<"inicio\n";
break;
case 79:
cout <<"fin\n";
break;
case ARR:
C.Mover(C.GetX()-3,C.GetY());
break;
case ABA:
C.Mover(C.GetX()+3,C.GetY());
break;
case IZQ:
C.Mover(C.GetX(),C.GetY()-3);;
break;
case DER:
C.Mover(C.GetX(),C.GetY()+3);
break;
default :
cout<<"0+"<<ch<<endl;
}
break; // del case 0:
}
}

closegraph();
return 0;
}
- 150 -
UNLaR - APUNTES DE PROGRAMACIÓN
Prof. Ing. Marcelo Daniel Camargo

El puntero this
El puntero this es una variable predefinida para todas las funciones de una clase. Este puntero
contiene la dirección del objeto concreto de la clase, al que se le está aplicando la función miembro.
Se puede decir que *this es un alias del objeto correspondiente.
Conviene tener en cuenta que cuando una función miembro se aplica a un objeto de su clase (su
argumento implícito), accede directamente a las variables miembro (sin utilizar el operador punto o
flecha), pero no tiene forma de referirse al objeto como tal, pues no le ha sido pasado explícitamente
como argumento. Este problema se resuelve con el puntero this.
En el caso de operadores miembro sobrecargados, tema que se abordará luego, el puntero this es
la forma que se utiliza para referirse al objeto al que se está aplicando el operador.
Hay que señalar que las funciones friend (funciones “no miembro”, que acceden a la clase) no
pueden usar el puntero this.
Ej.
char * alumno::getnombre()
{ return this->nombre;} /* En este caso es lo mismo que return nombre */
Un ejemplo del uso del puntero this es el retornar la dirección de memoria del objeto:alumno

alumno * alumno::getdir alumno()


{ return this;
}

Sobrecarga
Sobrecarga de funciones
La sobrecarga (overload) de funciones, es una característica que incorpora el C++, para dar soporte
al polimorfismo de la programación orientada a objetos, sin embargo, podemos hacer uso de ella sin
programar orientado a objetos.
La sobrecarga consiste en declarar varias funciones que tienen un mismo nombre, pero distinto
comportamientos. Dichas funciones se definen de forma diferente condicionado a sus argumentos.
En el momento de la ejecución se llama a una u otra función dependiendo del número y/o tipo de
argumentos en la invocación de la función. Por ejemplo, se pueden definir varias funciones para
calcular el valor absoluto de una variable, todas con el mismo nombre abs(), pero cada una acepta
un tipo de argumento diferente y con un valor de retorno diferente. Cabe aclarar, que la sobrecarga
de funciones es aplicable a cualquier funcion del C++ (de librerías estándar y de usuario) y para dar
soporte a la POO, a las que son miembros de una clase.
La sobrecarga no admite que las funciones difieran sólo en el tipo del valor de retorno, pero con el
mismo número y tipo de argumentos. De hecho, el valor de retorno no influye en la determinación
de la función que es llamada; sólo influyen el número y tipo de los argumentos.
Tampoco se admite que la diferencia sea el que en una función un argumento se pasa por valor y
en otra función, ese argumento se pasa por referencia.
Se presenta, a continuación, un ejemplo de dos funciones sobrecargadas, llamadas ambas
string_copy(), que copia cadenas de caracteres. Una de tiene dos argumentos y la otra tres.
Cada una de ellas llama a una de las funciones estándar del C: strcpy() que requiere unicamente
dos argumentos, y strncpy() que requiere a los tres. El número de argumentos en la llamada
determinará la función concreta que vaya a ser ejecutada:

La funcion sobrecargada es copiastring:

inline void copiastring(char *copia, const char *original);

inline void copiastring(char *copia, const char *original, const int longitud);

El programa que implementaría esta función sobrecargada podría ser el siguiente:

- 151 -

También podría gustarte