[C con Clase] Dudas sobre el capítulo 15: parámetros por referencia

Steven Richard Davidson stevenrichard.davidson en gmail.com
Mie Ene 9 12:53:41 CET 2008


Hola José Luis,

On Jan 8, 2008 8:23 PM, JoseL <joselubar en gmail.com> wrote:
>
> Hola, tengo un par de dudas relacionadas con los "parámetros por referencia" del capitulo 15.

[CORTE]

> ¿es p == q? es decir ¿son 'a' y 'r' la misma variable, la misma dirección de memoria, pero con distinto nombre, o bien son variables distintas, ocupando distintas direcciones de memoria, aunque tomen el mismo valor?
>

Sí, el valor de 'p' es igual al de 'q'; o sea, guardan la misma
dirección de memoria. De todas maneras, puedes comprobar esto
imprimiendo los contenidos de 'p' y 'q' o incluso con un 'if'. Por
ejemplo,

cout << "p = " << p << "  =  " << q << " = q\n";

O si lo prefieres,

if( p == q )
  cout << "p == q";
else
  cout << "p != q";
cout << endl;

> Y otra cuestión que me ronda ¿Para qué queremos las referencias si podemos hacer lo mismo con los punteros? me explico: ¿No da lo mismo hacer
>         int &r = a
> y usar 'r' como referencia, que hacer
>         int *p;
>         p = &a;
> y usar *p ?
>
> Es como si fuera lo mismo pero dado la vuelta, como las potencias y las raices. Y para manipular la variable 'a' ¿qué diferencia hay en la práctica pasarla por referencia, como en la función 'int Mas1Cuadrado(int &n)' o utilizar un puntero como en 'int Mas1Cubo(int *q)' ?

Efectivamente, no tiene mucho sentido usar referencias si tenemos
punteros, o viceversa. Los punteros tienen su origen en C, mientras
que las referencias se "agregan" en C++. El uso de referencias nos
sirve para manipular más fácilmente las entidades ya que prácticamente
son variables y constantes "originales". Con punteros, tenemos que
aplicar varios operadores para manejar los valores apuntados. Esto
significa que las expresiones pueden complicarse. Con esta falta de
legibilidad se puede provocar errores. Esto se ve en el código
anterior con la implementación de 'Mas1Cuadrado()'.

Una de las ventajas de usar punteros al igual que referencias es
cuando queremos pasar datos que ocupan muchos bytes. Típicamente, no
pasamos estructuras, ya que suelen ocupar varios bytes. En su lugar,
pasamos su dirección de memoria, o en el caso de referencias, la
referencia a tal variable. Por ejemplo,

struct info
{
  double fPrecio;
  unsigned long int nCant;
  double *pLista;
};

bool esTolerable( const info &ref, const double &fTol );

Con las referencias, podemos pasar las variables sin agregar operandos
como sería el caso de usar punteros. La otra practicalidad de usar
referencias es cuando se invocan funciones automáticamente. Esto lo
verás más adelante cuando llegues a los capítulos de la POO.
Específicamente, el capítulo 29 trata de los constructores y en
especial del constructor copia:
http://c.conclase.net/curso/index.php?cap=029#P30_COPIA

Por último, también se usan referencias cuando queremos cambiar de
tipo. Por ejemplo,

unsigned char *ptr;
...
double &ref = (double) (ptr[4]);

Aquí no lo notarías mucho, pero sí cuando llegues a los temas de POO,
y en especial el concepto de herencia. Te doy un ejemplo adelantado,

class Persona  {...};
class Estudiante : public Persona  {...};
...
Persona obj;
Estudiante &ref = obj;


En general, usamos referencias cuando realmente los necesitemos, como
es el caso de aceptar parámetros pasados a funciones para reducir la
cantidad de bytes transferidos. Sin embargo, no es aconsejable usar
referencias para aquellas funciones que no dejen claramente la
intención del uso de tales parámetros. Por ejemplo,

int sumar( int &a, int &b )
{
  return a++ + b++;
}

Obviamente, esta función encubre la tarea agregada e implícita de
incrementar los valores de ambos operandos: 'a' y 'b'. Desde el punto
de vista de diseño, esto no es recomendable. Si usáramos punteros,
entonces es más aparente que queremos manipular los valores de ambos
parámetros de forma indirecta.

Te pongo otro ejemplo en el que sí es adecuado usar referencias:

int incrementar( int &a )  { return ++a; }
void intercambiar( int &a, int &b )
{
  int temp = a;
  b = a;
  a = temp;
}


Espero que todo esto aclare el tema.

Steven




Más información sobre la lista de distribución Cconclase