viernes, 31 de agosto de 2018

C++ El apuntador This



El apuntador This

En C++, cada objeto tiene acceso a su propia dirección a través de un puntero o apuntador denominado This. Los objetos, utilizan el apuntador this de manera implícita, o sea que internamente el compilador utiliza ese apuntador.
Cuando nosotros escribimos:

cout << variable;

Lo que sucede internamente es:

cout << this -> variable;

También es válido escribir:

cout << (*this).variable;

Las tres instrucciones son equivalentes, siendo la última una forma para des referenciar el objeto.
Con lo cual, ambas instrucciones producen el mismo resultado. Como se puede apreciar, el puntero this, lo precede un operador de flecha (->), este operador es utilizado cuando se trabaja con punteros.
Todo lo anterior es posible con las funciones miembro no static del objeto. Cuando estudiemos los miembros de clase static, veremos que el puntero this no se pasa implícitamente a las funciones miembro static.

Uno de los usos que podemos hacer con el puntero this al utilizarlo de manera explícita, es evitar que un objeto se asigne a si mismo, esto conlleva graves errores si un objeto contiene apuntadores a almacenamiento asignado en forma dinámica. (esto también lo veremos más adelante). Otro uso que también podemos darle al apuntador this es permitir llamadas en cascada a funciones (como veremos en esta oportunidad), como también podemos sobrecargar operadores (que también veremos en esta oportunidad)

Observemos el siguiente ejemplo:

#include<iostream>
using std::cout;
using std::endl;

class Ejemplo{
  public:

    Ejemplo(int num):
      numero(num){}

    void imprimir(){
      cout << numero << endl;
      cout << this -> numero << endl;
      cout << (*this).numero << endl;
    }

  private:
    int numero;
};

int main(){

  Ejemplo mostrar(10);
  mostrar.imprimir();

return 0;
}

Este código produce el siguiente resultado:



Como se puede apreciar, las tres instrucciones muestran el mismo resultado.
Con este ejemplo, quiero dejar en claro que el apuntador this, se puede utilizar en forma implícita y explícita.

Llamada en cascada a funciones

Las llamadas en cascada a funciones, se refieren a realizar varias invocaciones de funciones en la misma instrucción, por ejemplo al crear un objeto:
Obj        b;

Podemos llamar funciones de la siguiente manera:

b.funcion1(5).funcion2(10).funcion3(15);

En futuras lecciones veremos algunos usos que le podemos dar a las llamadas en cascada, lo que importa en esta lección, es ver los usos del puntero this.

En el siguiente ejemplo, se puede apreciar que se encuentra destacadas las funciones set, ya que estas tienen un tipo de retorno (Vehiculo &) que permiten las llamadas en cascada. El tipo de retorno debe ser igual al nombre de la clase. Esto permite devolver una referencia a un objeto de tipo Vehiculo, utilizando la instrucción  return *this

//Interface.h

#include<iostream>
using std::string;
#ifndef INTERFACE_H
#define INTERFACE_H

class Vehiculo{

  public:
    Vehiculo(string = "", string = "", string = "");
    Vehiculo &setTipo(string);
    Vehiculo &setMarca(string);
    Vehiculo &setModelo(string);

    string getTipo()const;
    string getMarca()const;
    string getModelo()const;

    void imprimir()const;

  private:
    string tipo;
    string marca;
    string modelo;
};

#endif // INTERFACE_H


//Funciones.cpp

#include<iostream>
using std::cout;
using std::string;
using std::endl;

#include "Interface.h"

Vehiculo::Vehiculo(string T, string M, string Mo):
  tipo(T), marca(M), modelo(Mo){}

Vehiculo &Vehiculo::setTipo(string T){
  tipo = T;
  return *this;
}
Vehiculo &Vehiculo::setMarca(string M){
  marca = M;
  return *this;
}
Vehiculo &Vehiculo::setModelo(string Mo){
  modelo = Mo;
  return *this;
}

string Vehiculo::getTipo()const{
  return tipo;
}
string Vehiculo::getMarca()const{
  return marca;
}
string Vehiculo::getModelo()const{
  return modelo;
}

void Vehiculo::imprimir()const{
  cout << "Tipo: " << tipo << endl;
  cout << "Marca: " << marca << endl;
  cout << "Modelo: " << modelo << endl;
}

//Inicio.cpp

#include<iostream>
using std::string;

#include "Interface.h"

int main(){

  Vehiculo v;
  v.setTipo("Auto").setMarca("Kia").setModelo("Morning");
  v.imprimir();

return 0;
}

Al compilar y ejecutar este ejemplo, este es el resultado:
 





Esto es todo por ahora, saludos.


Gustavo J. Cerda Nilo, Agosto 2018




martes, 24 de julio de 2018

C++ Funciones Friend


Funciones y clases Friend.

Por lo general, un miembro privado de una clase no puede ser accedido desde fuera de esa clase, sin embargo si una función que se encuentre fuera de la clase se declara como su amiga, entonces tiene permiso para acceder a los miembros de la clase.
El uso de funciones amigas se usa comúnmente cuando no se puede usar una función miembro para ciertas operaciones.
Para declarar una función amiga de una clase, se debe anteponer la palabra clave friend al prototipo de la función en la definición de la clase. Esta declaración puede hacerse en cualquier parte de la clase, pero por convención, se hace al principio. Para hacer su miembro accesible, la clase tiene que declarar la función como una amiga en su definición, no se puede ser amiga de una clase, sin que la clase entregue su amistad a la función.
Ejemplo:

#include<iostream>
using std::cout;
using std::endl;

class Amiga{

friend void modificar(Amiga &);

public:

  Amiga():
    x(0){}

  void imprimir() const{
    cout << x << endl;
  }

private:
  int x;
};

En esta primera parte podemos ver que la declaración de friend, aparece primero dentro de la clase.

friend void modificar(Amiga &);

Incluso antes de las declaraciones miembro public, como se dijo antes, las declaraciones friend, pueden aparecer en cualquier parte de la clase, pero por convención, se colocan al principio.
La función friend, debe llevar como argumento un objeto del tipo de la clase a la que va a acceder, por eso es que el argumento en este caso es "Amiga", el cual lleva el nombre de la clase. Además, el acceso es por referencia, por eso es que se utiliza el operador &.
Lo siguiente que destaqué en esta clase, fue la declaración de la variable  int x. Esto es debido a que esta es la variable que será modificada por la función. En un principio, esta variable es iniciada por el constructor con un valor de cero.
Posteriormente, nos encontramos con una función individual, al estilo del lenguaje C, la cual habíamos declarado previamente. Esta función no es miembro de la clase Amiga. El trabajo de esta función es modificar el valor de la variable x, por un valor de 10.

void modificar(Amiga &c){
  c.x = 10;
}

Luego, pasamos a la función main. En esta función vamos a crear un objeto cambio, de la clase amiga.

int main(){
Amiga cambio;

Una vez creado el objeto, llamamos a la función imprimir, la cual nos mostrará el valor inicial de la variable x, en este caso cero.

cambio.imprimir();

Posteriormente, se modificará el valor de esa variable, llamando a la función modificar (recordar que es una función amiga), pasando como argumento, el objeto creado.

modificar(cambio);

Por último, se llama nuevamente a la función imprimir, para verificar el valor de la variable x. En este caso, al haber modificado la variable, su valor pasó a ser 10.

cambio.imprimir();

Al compilar y ejecutar este código, muestra el siguiente resultado:



El código completo es el siguiente:

#include<iostream>
using std::cout;
using std::endl;

class Amiga{

friend void modificar(Amiga &);

public:

  Amiga():
    x(0){}

  void imprimir() const{
    cout << x << endl;
  }

private:
  int x;
};

void modificar(Amiga &c){
  c.x = 10;
}

int main(){

Amiga cambio;
cambio.imprimir();

modificar(cambio);
cambio.imprimir();

return 0;
}

Esto es todo por ahora, espero se entienda. Saludos.

Gustavo J. Cerda Nilo, Julio 2018

C++ El apuntador This

El apuntador This En C++, cada objeto tiene acceso a su propia dirección a través de un puntero o apuntador denominado This. Lo...