Apunte interesante sobre referencias en C++

Anuncio
MIGUEL Á. TOLEDO MARTÍNEZ
CONTENIDO DE LA LECCIÓN 16
USO DE REFERENCIAS EN C++
1. Introducción
2. Parámetros de referencia como alias
2.1. Ejemplo 16.1
3. Variables de referencia como alias
3.1. Ejemplos 16.2, 16.3, 16.4, 16.5
2
2
3
4
4
4. Utilice comentarios en sus programas para explicar las referencias
6
5. Reglas para trabajar con referencias
6
6. Lo que necesita saber
7
FUNCIONES – LECCIÓN 16
16-1
MIGUEL Á. TOLEDO MARTÍNEZ
LECCIÓN 16
USO DE REFERENCIAS EN C++
INTRODUCCIÓN
Dos maneras de invocar funciones en muchos lenguajes de programación son mediante
llamada por valor y llamada por referencia. Cuando se pasa un argumento utilizando una
llamada por valor, se hace una copia del argumento, la cual se pasa a la función llamada. Los
cambios a la copia no afectan el valor de la variable original en el invocador. Con esto se evitan
los efectos secundarios que tanto minan el desarrollo de sistemas de software correctos y
confiables.
En esta lección presentaremos los parámetros de referencia, que son el primero de dos
medios que tiene C++ para efectuar una llamada por referencia. Con una llamada por referencia,
el invocador le da a la función llamada la capacidad de acceder directamente a la información del
usuario y de modificarla si así lo desea.
Mostraremos cómo lograr la ventaje de desempeño de una llamada por referencia
mientras, de manera simultánea, se logra la ventaja de ingeniería de software de proteger contra
la corrupción a la información del invocador.
Un parámetro de referencia es un alias de su argumento correspondiente.
Objetivos de esta lección:
•
•
Declarar e inicializar una variable de referencia dentro de su programa.
Usar variables de referencia para cambiar el valor de un parámetro dentro de una función.
PARÁMETROS DE REFERENCIA COMO ALIAS
Un parámetro de referencia es un alias de su argumento correspondiente. Para indicar
que el parámetro de una función se pasa por referencia, simplemente ponga un ampersand (&)
después de la clase de datos del parámetro en el prototipo de la función; utilice la misma
convención al listar la clase de datos del parámetro en el encabezado de la función. Por ejemplo,
la declaración
int &contador
en un encabezado de función se leería como contador es una referencia a un int. En la llamada
de función, basta con mencionar por nombre a la variable y ésta se pasará por referencia.
Después, mencionar a la variable por su nombre de parámetro en el cuerpo de la función
llamada, de hecho hará referencia a la variable original del invocador, la cual podrá ser
modificada directamente en la función llamada. Como siempre el prototipo de la función debe
coincidir con su encabezado.
FUNCIONES – LECCIÓN 16
16-2
MIGUEL Á. TOLEDO MARTÍNEZ
Ejemplo 16.1
El siguiente programa, REFERENCIA.CPP, compara una llamada por valor y una llamada por referencia
con parámetros de referencia. Los estilos de los argumentos de las llamadas a cuadradoPorValor() y
cuadradoPorReferencia(), son idénticos, es decir, ambas variables se mencionan simplemente por su
nombre. Sin revisar los prototipos de las funciones ni las definiciones de las funciones, es imposible saber,
a partir de las llamadas mismas, si las funciones pueden modificar sus argumentos. No obstante, debido a
que los prototipos de función son obligatorios, el compilador no tiene ningún problema para resolver esta
ambigüedad.
/* El siguiente programa: REFERENCIA.CPP, hace una comparación entre llamada por valor y
llamada por referencia con referencia.
*/
#include <iostream.h>
//Para cout y cin
int cuadradoPorValor(int);
void cuadradoPorReferencia(int &);
void main(void)
{
int x = 2, z = 4;
cout << "x = " << x << " antes de cuadradoPorValor()" << endl;
cout << "Valor devuelto por cuadradoPorValor(): " << cuadradoPorValor(x) << endl;
cout << "x = " << x << " después de cuadradoPorValor()" << endl << endl;
cout << "z = " << z << " antes de cuadradoPorReferencia()" << endl;
cuadradoPorReferencia(z);
cout << "z = " << z << " después de cuadradoPorReferencia()" << endl;
}//Fin de main()
int cuadradoPorValor(int a)
{
return a * a;
}//Fin de cuadradoPorValor()
void cuadradoPorReferencia(int &cRef)
{
cRef *= cRef;
}//Fin de cuadradoPorValor()
//El argumento del invocador no se modifica
//El argumento del invocador se modifica
En otra lección estudiaremos los apuntadores; veremos que los apuntadores permiten una
forma alterna de realizar una llamada por referencia donde el estilo de la llamada indica con
claridad que se trata de una llamada por referencia (así como el potencial de modificar los
argumentos del invocador)
Para especificar una referencia a una constante, ponga el calificador const antes de la
especificación de clase de dato en la declaración del parámetro.
Observe la colocación de & en la lista de parámetros de la función
cuadradoPorReferencia. Algunos programadores de C++ prefieren escribir int& cRef, en lugar
de int &cRef.
FUNCIONES – LECCIÓN 16
16-3
MIGUEL Á. TOLEDO MARTÍNEZ
VARIABLES DE REFERENCIA COMO ALIAS
Las referencias también pueden servir como alias de otras variables de la función. Por
ejemplo, el código:
int contador = 1;
int &cRef = contador;
++cRef;
//Declara la variable entera contador
//Crea cRef como alias de contador
//Incrementa contador (utilizando su alias)
Incrementa la variable contador por medio de su alias cRef. Las variables de referencia
deben inicializarse en sus declaraciones y no pueden reasignarse como alias a otras variables.
Una vez que una referencia se declara como alias de otra variable, todas las operaciones
efectuadas sobre dicho alias (es decir, la referencia) de hecho se realizan en la propia variable
original. El alias simplemente es otro nombre de la variable. Si se toma la dirección de una
referencia y se comparan las referencias, no sucede un error de sintaxis; en cambio, todas las
operaciones suceden en la variable para la que la referencia es un alias.
Las funciones pueden devolver referencias, pero esto puede ser peligroso. Al devolverle
una referencia a una variable declarada en la función llamada, la variable debe estar declarada
como static dentro de dicha función. De otra forma, la referencia es hacia una variable
automática que se descarta al terminar la función; se dice que tal variable esta indefinida y el
comportamiento del programa será impredecible (algunos compiladores emiten avisos cuando
esto sucede) Las referencia a variables indefinidas se llaman referencias colgantes.
Ejemplo 16.2
El siguiente programa REFINI1.CPP, ilustra el hecho de que toda variable referenciada debe de ser
inicializada.
/* El siguiente programa: REFINI1.CPP, ilustra el hecho de que toda variable referenciada
debe de ser inicializada.
*/
#include <iostream.h>
//Para cout y cin
void main(void)
{
int x
= 3;
int &y = x;
//Ahora ya es un alias de x
cout << "x = " << x << endl
<< "y = " << y << endl << endl;
y = 7;
cout << "x = " << x << endl
<< "y = " << y << endl << endl;
}//Fin de main()
FUNCIONES – LECCIÓN 16
16-4
MIGUEL Á. TOLEDO MARTÍNEZ
Ejemplo 16.3
El siguiente programa REFINI2.CPP, ilustra el hecho de no inicializar una variable de referencia.
/* El siguiente programa: REFINI2.CPP, ilustra el hecho de no inicializar una variable
por referencia.
*/
#include <iostream.h>
//Para cout y cin
void main(void)
{
int x = 3;
int &y;
//Ahora ya es un alias de x
cout << "x = " << x << endl
<< "y = " << y << endl << endl;
y = 7;
cout << "x = " << x << endl
<< "y = " << y << endl << endl;
}//Fin de main()
El compilador enviará el siguiente mensaje de error:
Reference variable ‘y’ must be initialized
Ejemplo 16.4
El siguiente programa: REFVAR.CPP, despliega y altera los valores de una variable usando la variable
misma o su referencia.
/* El siguiente programa: REFVAR.CPP, ilustra el uso de variables de referencia */
#include <iostream.h>
//Para cout y cin
void main(void)
{
int x
= 10;
int &rx = x;
// despliega x usando x y rx
cout << "x contiene " << x << endl;
cout << "x contiene (usando la referencia rx) "
<< rx << endl;
// altera x y despliega su valor usando rx
x *= 2;
cout << "x contiene (usando la referencia rx) "
<< rx << endl;
// altera rx y despliega el valor usando x
rx *= 2;
cout << "x contiene " << x << endl;
}//Fin de main()
FUNCIONES – LECCIÓN 16
16-5
MIGUEL Á. TOLEDO MARTÍNEZ
Ejemplo 16.5
El siguiente programa, INTCREF.CPP, utiliza referencias a dos datos de punto flotante para intercambiar
sus valores.
/* El siguiente programa: INTCREF.CPP, intercambia el valor entre dos variables utilizando
variables de referencia.
*/
#include <iostream.h>
//Para cout y cin
void intercambiaValores(float &a, float &b)
{
float temp;
temp
= a;
a
= b;
b
= temp;
}//Fin de intercambiaValores()
void main(void)
{
float grande
float pequeno
= 10000.0;
= 0.00001;
intercambiaValores(grande, pequeno);
cout << "Grande contiene: " << grande << endl;
cout << "Pequeño contiene: " << pequeno << endl;
}//Fin de main()
Como puede observar, la función intercambiaValores, se vuelve más fácil de comprender.
UTILICE COMENTARIOS EN SUS PROGRAMAS PARA EXPLICAR LAS REFERENCIAS
Como las referencias dentro de una función no utilizan asterisco, puede pensarse que el
valor de los parámetros no cambian, razón por la cual se hace necesario escribir comentarios
antes y dentro de las funciones que cambian parámetros utilizando referencias.
REGLAS PARA TRABAJAR CON REFERENCIAS
Una referencia no es una variable. Una vez que asigna un valor a la referencia, la
referencia no puede cambiar. Además, a diferencia de los apuntadores, no puede realizar las
operaciones siguientes en las referencias:
•
•
•
•
•
No puede obtener la dirección de la referencia utilizando el operador de dirección de
C++.
No puede asignarle un apuntador a una referencia.
No puede comparar valores de referencias utilizando los operadores relacionales de
C++.
No puede realizar operaciones aritméticas con una referencia, tal como agregarle un
desplazamiento.
No puede cambiar una referencia.
FUNCIONES – LECCIÓN 16
16-6
MIGUEL Á. TOLEDO MARTÍNEZ
LO QUE NECESITA SABER
Antes de continuar con la siguiente lección, asegúrese de haber comprendido los
siguientes conceptos:
!"C++ ofrece una forma directa de llamada por referencia, empleando parámetros de referencia.
Para indicar que el parámetro de una función se pasa por referencia, ponga en el prototipo de función,
después del tipo del parámetro, un &. En la llamada de la función, mencione por nombre a la variable y
será pasada como una llamada por referencia. En la función llamada, la mención de la variable con su
nombre local en realidad hace referencia a la variable original del invocador. Por lo tanto, la función
llamada puede modificar la variable original.
!"También se pueden crear parámetros de referencia para utilizarlos localmente como alias de
otras variables dentro de una función. Las variables de referencia deben inicializarse en sus
declaraciones y no se pueden reasignar como alias de otras variables. Una vez declarada una variable
de referencia como alias de otra variable, todas las operaciones supuestamente efectuadas sobre el alias
en realidad se llevan a cabo en la variable.
!"Una referencia en C++ es un alias (o segundo nombre) al nombre de una variable.
!"Para declarar una referencia, coloque el carácter ampersand (&) inmediatamente después del tipo de
variable y luego especifique el nombre de la referencia seguido por un signo igual y el nombre de la
variable a la que la referencia le dará un alias.
!"Una vez que asigna un valor a la referencia, no puede cambiar el valor de la misma.
!"Debe de incluir comentarios antes y dentro de las funciones que utilizan referencias para
cambiar el valor de un parámetro. De esta manera se asegura que otro programador que lea su
programa pueda reconocer los cambios que está realizando.
!"Un sobreuso de referencias puede conducir a programas poco legibles.
FUNCIONES – LECCIÓN 16
16-7
Descargar