47
Clases y objetos Clases y objetos en C++ en C++ Informática II - 2012 Informática II - 2012

Clases y objetos en C++ - dsi.fceia.unr.edu.ar · Uso de referencias en C++ • Una referencia es un alias de otra variable del mismo tipo, un equivalente completo de ella ... en

Embed Size (px)

Citation preview

Clases y objetos Clases y objetos en C++en C++

Informática II - 2012Informática II - 2012

Constructor no-argConstructor no-argclass Point3D {int x;//campos private por defectoint y;int z;public://uso lista de inicializadores Point3D (int x1, int y1, int z1): x(x1), y(y1), z(z1) {}Point3D (): x(0), y(0), z(0) {}//no arg, inicializa al origenPoint3D (int low, int high);//....};//en Point3D.cppPoint3D::Point3D (int low, int high) {x = low + int((rand() / RAND_MAX)) * (high - low);y = low + int((rand() / RAND_MAX)) * (high - low);z = low + int((rand() / RAND_MAX)) * (high - low);}//en main(), Point3D pt1;para el no-arg

Métodos get y setMétodos get y setclass Atleta{

char* nombre;//por defecto son private estos campos

int numero;

char* nacionalidad;

double tiempo;

public:

Atleta(char* n=NULL, int nro=0, char* p=NULL, double t=0.0);

char* getNombre(void) const;//tiene 2 cadenas con NULL, por defecto

int getNumero(void) const;

char* getNacionalidad(void) const;

double getTiempo(void) const;

void setNombre(char* n);

void setNumero(int n);

void setNacionalidad(char* n);

void setTiempo(double t);

void mostrarDatos(void) const;

~Atleta(void);};

Métodos get y setMétodos get y setAtleta::Atleta(char* n, int nro, char* p, double t){

nombre=new char[strlen(n) + 1];//reserva memoria dinámica

strcpy(nombre, n);

numero=nro;

nacionalidad=new char[strlen(p)+1];

strcpy(nacionalidad, p);

tiempo=t;}

char* Atleta::getNombre(void) const{

return nombre;}

void Atleta::setNombre(char *n) {

if(nombre==NULL){//si usé valores por defecto en el constructor

nombre=new char[strlen(n) + 1];//idem constructor para nombre

strcpy(nombre, n);}}

Métodos constMétodos const

//en Point3D.h

//no puedo escribir un campo en el lado izquierdo de

//asignación dentro de la definición de la función

//declarada const

//una función const no puede invocar un método de

//la clase Point3D que no haya sido declarado const

bool equals(Point3D q) const;//const al final header

bool equals(int x1, int y1, int z1) const;

Puntero thisPuntero thisbool Point3D::equals(Point3D q) const {//no hace falta el this

return (this->x == q.x && this->y == q.y && this->z == q.z);}

//función sobrecargada, distintos argumentos

bool Point3D::equals(int x1, int y1, int z1) const {//sin puntero this

return (x == x1 && y == y1 && z == z1);}

//en main(), compara punto pt4 con punto pt2 (2º versión)

cout << "Es este nuevo punto transladado pt4 igual a pt2? --> " << pt4.equals(pt2.getX(), pt2.getY(), pt2.getZ()) << endl;//simétrico

//primera versión de equals

cout << "Punto 1 ahora es: ( "<< pt1.getX() << ", " << pt1.getY() << ", " << pt1.getZ() << ")" << endl;

cout << "Es pt1 igual a pt2? --> "<< pt1.equals(pt2) << endl;

Argumentos por defectoArgumentos por defecto#pragma once

class Punto{double x;//privados por defectodouble y;

public:

Punto(double cx=0.0, double cy=0.0);

~Punto(void);//los args.por defecto

double getX(void);

double getY(void);

void setX(double cx);

void setY(double cy);

void mover(double dx, double dy);

void mostrarPunto(void);};

Argumentos por defectoArgumentos por defectoPunto::Punto(double cx, double cy){

x=cx;y=cy;}

//Tengo clases contenedorasclass Circulo{public:

Circulo(double r=1.0, double x=0.0, double y=0.0);double getRadio(void);void setRadio(double r);double area(void);void mostrarCirculo(void);void mover (double dx, double dy);~Circulo(void);

private:double radio;Punto centro;//contiene un objeto Punto como centro

};

Argumentos por defectoArgumentos por defecto//Forma correcta de inicializar en Circulo.cppCirculo::Circulo(double r, double x, double y):centro(x,y){

radio=r;}//Tengo otra clase contenedoraclass Anillo{public:

Anillo(double x=0.0, double y=0.0, double radio=1.0, double a=1.0);double getAncho(void);void setAncho(double a);double area(void);void mover(double dx, double dy);void mostrarAnillo(void);~Anillo(void);

private:Circulo interior;//contiene dos circulosCirculo exterior;double ancho;

};

Argumentos por defectoArgumentos por defecto

//Anillo.cpp

#include "Anillo.h"

//forma correcta de inicializar los dos circulos contenidos

Anillo::Anillo(double x=0.0, double y=0.0, double radio=1.0, double a=1.0):interior(x,y,radio), exterior(x,y,radio+ancho)

{

ancho=a;

}

Argumentos por defectoArgumentos por defecto#include <iostream>

using std::cout;

using std::endl;

class CStack{

public:

CStack(int n = 10);//pila con 10 elementos por defecto

~CStack();

void push(int i);

int pop();

void print();

private:

int* pList;//reserva dinámica de memoria

int size;

int next;};

Argumentos por defectoArgumentos por defecto

CStack::CStack(int n) : next(0), size(n){//siguiente es 0 al inicio

pList = new int[size];//luego next++;por cada inserción

}

Arrays de objetos de una Arrays de objetos de una claseclase

class Carriage {bool asientos [40]; bool primera;

public:Carriage() {};//no argCarriage(bool prim);bool getAsiento(int ind) { return asientos[ind]; }bool getPrimera() { return primera; }void setPrimera(bool p) { primera = p; }void ocupar();

};

Arrays de objetos de una Arrays de objetos de una claseclase

class Train {

Carriage * carriages;//reservo memoria dinámica para el array

int numPri;

int numSeg;

char * salida;

char * destino;

int precioPrimera;

int precioSegunda;

public: Train(int nP, int nS, char * sal, char * dest, int pP, int pS):

numPri(nP), numSeg(nS), salida(sal), destino(dest), precioPrimera(pP), precioSegunda(pS) {carriages = new Carriage[nP + nS];//crea array

for(int i = 0; i < nP + nS; i++) carriages[i].setPrimera(i < nP);}

~Train() { delete [] carriages; }

Carriage getCarriage(int i) { return carriages[i]; }

void llenar();

int totalVentas();};

Arrays de objetos de una Arrays de objetos de una claseclase

//pruebaSala.cpp

//…faltan include y using

int main(void){

Sala s1("Sala 1", 8,12,true);

Sala s2("Sala 2", 18,20,false);

Sala s3("Sala 3", 12,15,true);

Sala s[]={s1,s2,s3};

s1.mostrarDatos();

int eventos[4]={200,50,100,150};

for(int i=0;i<4;i++)

for(int j=0;j<3;j++)

if(s[j].calculaCapacidad()>=eventos[i])

cout<<"La sala "<<s[j].getNombre()<<" tiene capacidad para "<<eventos[i]<<" personas\n\n";

return 0;}

Miembros static de una Miembros static de una claseclase

class Camion {//clase de la práctica modificadaint nroruedas;static int nrocamiones;

public:

Camion(int nror);

//…

static int nroCamiones(void);

~Camion(void);};

Camion::Camion(int nror){

nroruedas=nror;

nrocamiones++;}//cuento camiones creados

int Camion::nrocamiones=0;//inicializo fuera de la //declaración!!

Miembros static de una Miembros static de una claseclase

//en Camion.cpp

int Camion::nroCamiones(void){

return nrocamiones;}

//archivo de prueba.cpp

int main(void)

{

Camion c(6);

Camion d(8);

cout<<"El nro. de camiones creados es: "<<Camion::nroCamiones()<<"\n";//2 camiones creados

return 0;

}

Punteros a objetos de una Punteros a objetos de una claseclase

class Carrera2{

int distancia;

Atleta** competidores;//array de Atletas manejados por *

int cantAtletas;

int indice;

public:

Carrera2(int d, int cantidad);

int getDistancia(void) const;

Atleta *getGanador(void) const;

int getCantAtletas(void) const;

void agregarAtleta(Atleta* p);

~Carrera2(void);};

Punteros a objetos de una Punteros a objetos de una claseclase

Carrera2::Carrera2(int d, int cantidad){

distancia=d;

cantAtletas=cantidad;

competidores=new Atleta* [cantidad];

indice=0;}

Atleta* Carrera2::getGanador(void) const{

double t=competidores[0]->getTiempo();//Uso de ->

double taux;

int iaux;

for(int i=1;i<cantAtletas;i++){

taux=competidores[i]->getTiempo();

if(taux<t){

t=taux;

iaux=i; }}

return competidores[iaux];}

Punteros a objetos de una Punteros a objetos de una claseclase

void Carrera2::agregarAtleta(Atleta* p){

if(indice<cantAtletas){

competidores[indice]=p;

indice++;

}}

Carrera2::~Carrera2(void)

{

delete[] competidores;

}

Punteros a objetos de una Punteros a objetos de una claseclase

int main(void){

Atleta a1("Juan Perez",1, "Argentina", 10.1);

Atleta a2("John Ford",2,"USA", 9.1);

Atleta *p=new Atleta("Juan Castro", 3, "Mexico", 7.3);

Carrera2 c3(300,3);

c3.agregarAtleta(&a1);

c3.agregarAtleta(&a2);

c3.agregarAtleta(p);

Atleta *r=c3.getGanador();

r->mostrarDatos();//acceso indirecto a través de *

delete p;//muestradatos del atleta ganador

return 0;}

Uso de referencias en C++Uso de referencias en C++• Una referencia en principio parece muy

similar a un puntero• Su importancia real se vuelve aparente

con su uso en argumentos de funciones, en especial en el contexto de la programación orientada a objetos

• A pesar de su simplicidad es un elemento muy potente y en algunos contextos alcanzaría resultados que serían imposibles de obtenerlos sin ellas

Uso de referencias en C++Uso de referencias en C++• Una referencia es un alias de otra variable

del mismo tipo, un equivalente completo de ella

• Es un nombre que puede usarse en lugar del nombre de la variable original. Debido a que es un alias y no un puntero, la variable de la cual es un alias tiene que especificarse cuando se declara dicha referencia y, a diferencia de un puntero, una referencia no puede alterarse para representar a otra variable (tampoco puede valer NULL)

Declaración e inicialización Declaración e inicialización de referenciasde referencias

• long number=0;• long& rnumber = number; // Declara una

//referencia a la variable number,• long &rnumber;//error• rnumber += 10;//number=10;• long* pnumber = &number; // Inicializa • //el puntero con la dirección de number• *pnumber += 10; // Incrementa number • //a través de un puntero• Al puntero necesito desreferenciarlo para usarlo,

a la referencia no

Declaración e inicialización Declaración e inicialización de referenciasde referencias

#include <iostream>

using std::cout;using std::endl;int main(){int a=10;int&b=a;cout<<&a<<"\t"<<&b<<endl;return 0;}Salida por pantalla:Parece puntero a dirección fija de memoria0012FF60 0012FF60 Presione una tecla para continuar . . .

Declaración e inicialización Declaración e inicialización de referenciasde referencias

• Pueden inicializarse a referencias del mismo tipo, en cuyo caso señalan al objeto inicial:

int& max (int& a, int& b) {

return (a >= b)? a : b;

}...

int x = 10, y = 30;

int& r1 = x; // Ok. r1 referencia a x

int& r2 = r1; // Ok. r2 referencia a x

int& r3 = max(x, y); // Ok. r3 referencia a y

Declaración e inicialización Declaración e inicialización de referenciasde referencias

• Después de la asignación inicial, las sucesivas asignaciones a las referencias deben ser con objetos del mismo tipo. Por ejemplo, a una referencia a int solo se le pueden asignar tipos int. Pero estas asignaciones son en realidad al objeto inicialmente referenciado.

int x = 10, y = 20;

int& refi = x; // definición inicial

cout << "X = " << refi; // -> X = 10 (valor de x)

refi = y; // Ojo!! Equivale a: x = y

cout << "X = " << refi; // -> X = 20 (x es ahora 20)

cout << "X = " << x; // -> X = 20 (comprobación)

Referencias como Referencias como argumentos de funcionesargumentos de funciones

// Funcion que incrementa una variable en 10int incr10(int& num) {//la ref.se crea e inicializa c/vez que //la función es invocada, o sea c/vez se crea

//una nueva referenciacout << endl<< “Valor recibido = “ << num;num += 10; // Incrementa el argumentoreturn num; // retorna el valor incrementado}//verdadero paso por referencia, en caso de

//punteros se pasa una copia del mismo, en C//se emula el paso por referencia con punteros//sino se quiere modificar el arg.se agrega const

Referencias como Referencias como argumentos de funcionesargumentos de funciones

int main(void){

int num = 3;

int value = 6;

int result = incr10(num);//error: incr10(20);una cte.no puede //modificarse!

cout << endl<< “incr10(num) = “ << result;

cout << endl<< “num = “ << num;

result = incr10(value);

cout << endl<< “incr10(value) = “ << result;

cout << endl<< “value = “ << value;

cout << endl;

return 0;}

Referencias como Referencias como argumentos de funcionesargumentos de funciones

Valor recibido = 3

incr10(num) = 13

num = 13

Valor recibido = 6

incr10(value) = 16

value = 16

RecomendacionesRecomendaciones• Cuando la función llamada no altera sus

argumentos, se debe pasar una copia de la variable.

• Cuando una función cambia el valor de sus argumentos, se debe pasar la dirección, a través de punteros.

• Las referencias se reservan para aquellos casos en los que la función no cambiará sus argumentos, pero en los que es deseable pasar una referencia (es decir, un puntero) a la variable en lugar de una copia de la variable. Esto ocurre cuando una variable grande, (una estructura o un objeto de alguna clase) se pasa como argumento.

Funciones que retornan Funciones que retornan referenciasreferencias

#include <iostream>#include <iomanip>using std::cout;using std::endl;using std::setw;double& lowest(double values[], int length); int main(void){double array[] = { 3.0, 10.0, 1.5, 15.0, 2.7, 23.0,4.5, 12.0, 6.8, 13.5, 2.1, 14.0 };//no puedo crear arrays de referenciasint len = sizeof array/sizeof array[0]; cout << endl;for(int i = 0; i < len; i++)

cout << setw(6) << array[i];lowest(array, len) = 6.9; // Change lowest to 6.9, cambia array[2]lowest(array, len) = 7.9; // Change lowest to 7.9,cambia array[10]cout << endl;//Raro lo anterior!,se puede hacer con * pero asífor(int i = 0; i < len; i++)//más sencillocout << setw(6) << array[i];cout << endl;return 0;}

Funciones que retornan Funciones que retornan referenciasreferencias

double& lowest(double a[], int len){int j = 0; // Index of lowest elementfor(int i = 1; i < len; i++)if(a[j] > a[i]) // Test for a lower value...j = i; // ...if so update jreturn a[j]; // Return reference to lowest// element//ídem a retornar un double, si hubiese retornado un puntero:&a[j];}

3 10 1.5 15 2.7 23 4.5 12 6.8 13.5 2.1 14 3 10 6.9 15 2.7 23 4.5 12 6.8 13.5 7.9 14Presione una tecla para continuar . . .//podría usar el valor de retorno del lado derecho del = //lowest(x, lenx) = 2.0*lowest(y, leny);//al igual que con punteros: nunca retornar referencias a variables locales

Referencias a objetos de Referencias a objetos de una claseuna clase

class Candado{int programado[3];int actual[3];};

public:

Candado(int []);

void alterardigito(int i, int nro);

bool puedeAbrir()const;

bool mismaCombinacionActual(const Candado &c)const;

~Candado(void);

bool Candado::mismaCombinacionActual(const Candado &c)const{

for(int i=0;i<3;i++)

if(actual[i]!=c.actual[i])

return false;

return true;}

Referencias a objetos de Referencias a objetos de una claseuna clase

int main(void){

int p1[]={3,2,1};

int p2[]={1,2,3};

Candado c1=Candado(p1);

Candado c2=Candado(p2);

if(c1.mismaCombinacionActual(c2))

cout<<"Los dos candados tienen la misma combinacion actual\n";

else

cout<<"Los dos candados no tienen la misma combinacion actual\n";

return 0;

}

Constructor de copiaConstructor de copiaclass CSimpleString{

size_t len;

char* buff;

public:

CSimpleString(const char* p = 0);

CSimpleString(const CSimpleString& s);// constructor copia

void print(){cout << buff;}

~CSimpleString();

};

CSimpleString::CSimpleString(const CSimpleString& s){

len = s.len;

buff = new char[len+1];

strcpy_s(buff, len+1, s.buff);}

Constructor de copiaConstructor de copiaint main(){

CSimpleString s1 = "hello";

CSimpleString s2 =s1;

cout << "s1 = \"";

s1.print();

cout << "\"" << endl;

cout << "s2 = \"";

s2.print();

cout << "\"" << endl;

return 0;}

Destructores y asignación Destructores y asignación dinámica de memoriadinámica de memoria

CSimpleString::CSimpleString(const char* p) : len(0), buff(0){

if (p != 0) {

len = strlen(p);

if (len > 0) {

buff = new char[len+1];

strcpy_s(buff, len+1, p);

} }}

CSimpleString::~CSimpleString()

{

delete []buff;

}

Destructores y asignación Destructores y asignación dinámica de memoriadinámica de memoria

Atleta::Atleta(char* n, int nro, char* p, double t){

nombre=new char[strlen(n) + 1];

strcpy(nombre, n);

numero=nro;

nacionalidad=new char[strlen(p)+1];

strcpy(nacionalidad, p);

tiempo=t;}

Atleta::~Atleta(void){

delete[] nombre;

delete[] nacionalidad;

cout<<"Se invoca al destructor de atleta\n";

}

Destructores y asignación Destructores y asignación dinámica de memoriadinámica de memoria

EsONoMagica::EsONoMagica(int **m, int f, int c){

filas=f;

columnas=c;

//reservo espacio para el vector que apunta a las filas

matriz=new int*[f];

//reservo memoria para las columnas de cada fila

for(int i=0;i<c;i++)

matriz[i]=new int[c];

//llena con datos

for(int i=0;i<filas;i++)

for(int j=0;j<columnas;j++)

matriz[i][j]=m[i][j];}

Destructores y asignación Destructores y asignación dinámica de memoriadinámica de memoria

EsONoMagica::~EsONoMagica(void)

{

//libera la memoria de la matriz

for(int i=0;i<filas;i++)

delete[]matriz[i];//libera columnas

delete[]matriz;//libera filas

}

Sobrecarga de operadoresSobrecarga de operadores

//uso referencia para evitar copia y const porque no modifica el objeto

bool Point3D::operator>(const Point3D& q) const {

return (this->distanceOrigin()>q. distanceOrigin());

}

Sobrecarga de operadoresSobrecarga de operadores

//debe retornar referencia por características de la asignación y asociatividad de derecha a izquierda (permite concatenar operaciones)

CSimpleString& CSimpleString::operator=(const CSimpleString& rhs){

len = rhs.len;//operación modifica operando izquierdo

delete buff;//primero borra memoria asignada

buff = new char[len+1];//ahora copia

strcpy_s(buff, len+1, rhs.buff);//objeto invocador el del lado izqq.del =

return *this;}//retorna resultado operación en el mismo objeto,

//A.operator=(B); o A=B;

//por si hago A=A; debería en 1º lugar hacer:

if(this==&rhs)//chequea direcciones y si son iguales

return *this;//retorna primer operando

Sobrecarga de operadoresSobrecarga de operadoresint main(){

CSimpleString s1 = "hello";

CSimpleString s2 = "goodbye";

cout << " After executing s2 = s1:" << endl;

s2 = s1;

cout << "s1 = \"";

s1.print();

cout << "\"" << endl;

cout << "s2 = \"";

s2.print();

cout << "\"" << endl;

return 0;

}

Sobrecarga de operadoresSobrecarga de operadoresCSimpleString CSimpleString::operator+(const CSimpleString& s)

{

size_t length = len + s.len + 1;

char* tmp = new char[length];

strcpy_s(tmp, length, buff);

strcat_s(tmp, length, s.buff);

return CSimpleString(tmp);

}

Sobrecarga de operadoresSobrecarga de operadores

CSimpleString::CSimpleString(const char* p) : len(0), buff(0){

if (p != 0){

len = strlen(p);

if (len > 0){

buff = new char[len+1];

strcpy_s(buff, len+1, p);

}}}

// Addition operator: CSimpleString object + string constant

CSimpleString CSimpleString::operator+(const char* s){

return *this + CSimpleString(s);}

Sobrecarga de operadoresSobrecarga de operadores// += operator

CSimpleString& CSimpleString::operator+=(const CSimpleString& rhs){

*this = *this + rhs;//usa los operadores + e =

return *this;

}

int main(){

CSimpleString s1 = "hello";

s1 += " world!";

cout << "s1 = \"";

s1.print();

cout << "\"" << endl;

return 0;}