variable una tipos sintaxis rangos programacion para funciones ejemplos definicion declarar declaracion constantes c++ variables reference

c++ - tipos - ¿Cuándo es apropiada una variable de referencia y por qué? ¿Puedes explicar la sintaxis real y la ubicación?



tipos de variables en c++ pdf (10)

Esta pregunta ya tiene una respuesta aquí:

Soy nuevo en C ++. Recientemente hemos comenzado a explorar las variables de referencia en clase, y estoy muy confundido acerca de ellas. No necesariamente cómo hacerlo, ya que entiendo que cambian los valores de las variables, sino más bien en la línea de POR QUÉ un desarrollador querría hacer una cosa así. ¿Qué logran ellos? ¿Guardan memoria? ¿Evitan tener que devolver información?

Aquí es parte del proyecto en el que estamos trabajando. Necesitamos incluir al menos una variable de referencia. Puedo ver cómo escribiría el programa sin la variable de referencia, pero no veo dónde una variable de referencia sería útil o necesaria.

"El usuario puede desear obtener una estimación de una a muchas habitaciones. Las tarifas se basan en los pies cuadrados de las paredes y / o el techo. La compañía estima que se necesitan 2.5 horas para pintar 200 pies cuadrados de espacio de la pared y 3.2 horas para pinte la misma área en el techo. La tasa de mano de obra es de $ 40 por hora. Si el trabajo para pintar WALLS totaliza más de 1400 pies cuadrados de espacio, el cliente recibe un descuento del 15% para todos los pies cuadrados que superen los 1400 pies cuadrados. Descuentos para techos de pintura.

El programa imprimirá un informe final de los costos estimados en un formato profesional.

El programa preguntará al usuario si desea realizar más cálculos antes de salir ".

No los estoy buscando para que hagan mi tarea, y para referencia, acabamos de terminar con las funciones de aprendizaje. Estoy bastante bien, pero hay MUCHAS cosas leyendo estos sitios que no entiendo.

Y, esencialmente, studentID se establecería en 21654. ¿Estoy entendiendo esto correctamente?

Intentemos esto de nuevo:

He revisado esta duplicación sugerida. Si bien cubre los aspectos básicos de los pros / contras de usar variables de referencia en lugar de indicadores y discute multitud de razones para usar ambas, sigo cuestionando la idea básica de cuándo (cuándo es apropiado y no es necesario) y por qué (por qué). es apropiado en ciertas circunstancias, ¿qué ventajas le da al programa?)

Debería usar tales variables y también cómo (la sintaxis y ubicación reales). Casi todos los que están aquí han sido excelentes, y he aprendido mucho sobre el tema a través de mis interacciones con ustedes. Aunque gran parte de esto es repetitivo e irritante para los programadores experimentados, todo esto es nuevo para mí, y necesitaba participar en la conversación tanto como necesitaba la información. He usado Stack Overflow para muchos proyectos, por ejemplo, aprendiendo sobre newString.equalsIgnoreCase () de Java, y admiro tu conocimiento. Solo puedo decirte la verdad, si eso no es lo suficientemente bueno, entonces es lo que es.

Bien, déjame revisar mi entendimiento hasta ahora:

Las variables de referencia tienden a reducir la modificación no deseada de las variables dentro de una función y / o programa.

Las variables de referencia se utilizan para modificar las variables existentes dentro de las funciones.

Esto es útil ya que "mueve" los valores al mismo tiempo que minimiza la copia de esos valores.

Las variables de referencia modifican las variables existentes dentro de las funciones / programas.

No sé si todavía pueden leer esto o no, ya que se ha marcado un duplicado. He estado jugando con algunos de los miniprogramas que me han dado, releído partes de mi libro, he investigado un poco más, etc., y creo que entiendo a nivel rudimentario. Estas variables de referencia le permiten alterar y / o usar otras variables dentro de su código sin tener que introducirlas directamente en su código. No puedo recordar qué usuario estaba usando el ejemplo foo (hubble, bubble), pero fue su código el que finalmente lo hizo clic. En lugar de solo usar el valor, en realidad está usando y / o reasignando la variable.


Casi siempre se podrían usar variables de referencia (en lugar de pasar por valor): por ejemplo ...

// this function creates an estimate // input parameter is the Rooms to be painted // passed as a const reference because this function doesn''t modify the rooms // return value is the estimated monetary cost Money createEstimate(const Rooms& rooms) { ... } // this function adds paint to the rooms // input parameter is the Rooms to be painted // passed as a non-const reference because this function modifies the rooms void paintRooms(Rooms& rooms) { ... }

Cuando pasas por valor en lugar de paso por referencia, creas y pasas implícitamente una copia de la cosa ...

// creates and passes a copy of the Rooms to the createEstimate function Money createEstimate(Rooms rooms) { ... }

... que (crear una copia) es (a menudo, un poco) más lento que pasar por referencia (además, crear una copia puede tener efectos secundarios).

Como posible optimización ligera del rendimiento, y por convención (porque a las personas no les importa), es común pasar de valor en lugar de pasar de referencia cuando el tipo es pequeño y simple (también conocido como tipo "primitivo"), por ejemplo:

// passes a copy of the x and y values // returns the sum int add(int x, int y) { ... }

... en lugar de ...

// passes a reference to x and y // returns the sum int add(const int& x, const int& y) { ... }

Consulte también Pasar un parámetro modificable a la función c ++ y ¿Por qué tener parámetros de puntero?


Daré tres razones, pero hay muchas más.

  1. Evitando copias innecesarias.

    Supongamos que escribes una función así:

    double price(std::vector<Room> rooms) { ... }

    Ahora, cada vez que lo llames, se copiará el vector de Room . Si solo calcula los precios de unas pocas habitaciones, está bien, pero si desea calcular el costo de volver a pintar la totalidad de las oficinas del Empire State Building, comenzará a copiar objetos enormes, y esto lleva tiempo.

    En este caso, es mejor utilizar una referencia constante que proporcione acceso de solo lectura a los datos:

    double price(const std::vector<Room>& rooms) { ... }

  2. Usando el polimorfismo

    Supongamos que ahora tiene diferentes tipos de habitaciones, tal vez un CubicRoom y un CylindricalRoom , que ambos heredan de la misma clase base, Room .

    No es posible escribir:

    double price(Room room) { ... }

    y luego llamar

    price(CylindricalRoom()); //or price(CubicRoom());

    pero puede hacerlo si define el price siguiente manera:

    double price(Room& room);

    Entonces todo funciona igual que si pasara por valor.

  3. Evitando devoluciones

    Supongamos que cada vez que calcula un precio, desea agregar una cotización con formato a un informe. En C ++ solo puede devolver un solo objeto desde una función, por lo que no puede escribir:

    return price, fmtQuote

    Sin embargo, usted puede hacer:

    double price(Room room, std::vector<std::string>& quotes) { ... quotes.push_back(fmtQuote); return price }

    Obviamente, podría devolver un par de objetos std::pair<double, std::string> , pero esto significa que la persona que llama debe desempaquetar el resultado. Si tiene la intención de llamar a menudo la función anterior, esto rápidamente se volverá feo. En este caso, esto se vincula con el primer punto: el registro de todas las comillas aumentará y no desea copiarlo para cada llamada.

    Este es un patrón de acceso típico para los recursos compartidos : desea que algunas funciones / objetos obtengan un identificador de un recurso, no una copia de ese recurso.


Estás mezclando dos cosas completamente separadas aquí. Tres ejemplos para mostrar cómo funcionan las dos cosas, individualmente y luego juntas ...

  1. Una función puede tomar un parámetro pasado por valor y devolver un valor.

    double foo (double y) { y = y + 200.0; return y; } void main(void) { double hubble = 50.0; double bubble = 100.0; hubble = foo(bubble); std::cout << "hubble=" << hubble << ", bubble=" << bubble << std::endl; }

    Tenga en cuenta que debido a que esto se pasa por valor, aunque foo () cambia y, la bubble no cambia. hubble se establece en el valor devuelto por foo ().

    Entonces tienes

    hubble=300, bubble=100

  2. Una función puede tomar un parámetro pasado por referencia y modificar ese parámetro.

    void foo (double& y) { y = y + 200.0; } void main(void) { double hubble = 50.0; double bubble = 100.0; foo(bubble); std::cout << "hubble=" << hubble << ", bubble=" << bubble << std::endl; }

    Entonces tienes

    hubble=50, bubble=300

    Por supuesto que el hubble no ha cambiado. Pero debido a que la bubble se pasó por referencia, el cambio a y dentro de foo () cambia a la bubble , porque ese cambio se está produciendo en la variable real aprobada y no en un valor copiado.

    Tenga en cuenta que no tiene una declaración de "devolución" aquí. La función no devuelve nada, simplemente modifica la variable que se le pasa.

  3. Y, por supuesto, pueden usar ambos juntos.

    double foo (double& y) { y = y + 200.0; return y + 400.0; } void main(void) { double hubble = 50.0; double bubble = 100.0; hubble = foo(bubble); std::cout << "hubble=" << hubble << ", bubble=" << bubble << std::endl; }

    Entonces tienes

    hubble=700, bubble=300

    Como antes, cambiar y dentro de foo () cambia la bubble . Pero ahora la función también está devolviendo un valor, que establece el hubble .

¿Por qué elegirías devolver un valor, o modificar el valor pasado, o hacer ambas cosas? Eso depende completamente de cómo escribas tu código.

Estoy de acuerdo con usted en que no tiene que usar un paso por referencia aquí. Yo mismo, probablemente solo devolvería un valor. Pero este es un ejercicio de aprendizaje, y se te ha dicho que lo hagas de esa manera, así que debes hacerlo. Supongamos que su paso por referencia es el descuento? Así que una función "descuento nulo (doble y valor)" toma el valor pasado y lo multiplica por 0.85. Es un poco artificial, pero demostraría el principio.


Hay otra ventaja, más general, de las referencias que los punteros no proporcionan. Las referencias por su propia naturaleza le permiten expresar a través de la firma de la función que el objeto al que se hace referencia debe existir en el momento en que se llama la función No se permiten nulos.

La persona que llama no puede esperar razonablemente una función que tome una referencia para verificar la validez de esa referencia.

Los punteros, por otro lado, pueden ser válidamente nulos. Si escribo una función que acepta un puntero ...

void increment(int* val) { (*val)++; }

... y la persona que llama proporciona un valor nulo, mi programa probablemente se bloquee. Puedo escribir toda la documentación que quiero indicando que el puntero no debe ser nulo, pero el hecho es que es bastante fácil que alguien lo pase accidentalmente. Así que si quiero estar seguro, debo verificarlo.

Pero escribe esta función con una referencia y la intención es clara. No se permiten nulos.


Las referencias se introdujeron principalmente para soportar la sobrecarga del operador. El uso de punteros para "pasar por referencia" le daría una sintaxis inaceptable según Bjarne Stroustrup. También permiten aliasing.

Además, permiten la programación orientada a objetos con una sintaxis más agradable que el uso del puntero explícitamente. Si está utilizando clases, debe pasar referencias para evitar el corte de objetos .

En resumen, siempre debe preferir el uso de referencias sobre punteros vacíos.


Las variables de referencia son punteros sin un * y prácticamente sin aritmética de punteros.

No son necesarios de C ++, solo son azúcar sintáctica a su alrededor.

La idea inicial de los creadores fue probablemente hacer que el código C ++ sea más comprensible, aunque alcanzaron su opuesto exacto.

Mi opinión es que un programa en C ++ es mejor si pierde por completo las variables de referencia y utiliza solo punteros.

Su función en el formulario.

double foo (double studentID* y) { *y = 21654; return *y; }

... haría exactamente lo mismo, pero en realidad sería mejor comprensible.


Las variables de referencia son una alternativa más segura a los punteros. Por lo general, cuando se trata de punteros, realmente no le importa el puntero ( ptr ) sino lo que apunta a ( *ptr ); y, sin embargo, todo el tiempo los programadores estropean y manipulan ptr lugar de *ptr y así sucesivamente. Considere este código:

void zeroize_by_pointer(int* p) { p = 0; // this compiles, but doesn''t do what you want }

Compare con la versión de referencia,

void zeroize_by_reference(int& p) { p = 0; // works fine }

Hay muchas otras razones por las que las referencias son una buena idea, pero para alguien que comienza en C ++, sugiero que se centre en esto: hace que sea un poco más difícil dispararse en el pie. Siempre que trate con punteros, tendrá que lidiar en algún nivel con el modelo de memoria de la máquina, y eso es bueno evitarlo cuando sea posible.


Los argumentos de referencia se utilizan más cuando pasas un objeto como argumento. De esa manera usted no copia toda la variable; Por lo general, vienen con un modificador const como:

void printDescription(const Person& person) { ... }

De esa manera usted no copia el objeto.

En algún momento el tipo de retorno también se establece como una referencia. De esa manera, está devolviendo el mismo objeto (y no una copia de él). Echa un vistazo al operador << de ostream. ostream& operator<< (streambuf* sb ); .

Con las variables puede pensar en el caso en el que puede intercambiar valores.

void swap(int & a, int & b) { int aux = a; int a = b; int b = aux; }

Este caso en Java, por ejemplo, tiene que hacerse de una manera más compleja.


También hay diferentes tipos de referencias. Tenemos referencias de rvalue y rvalue , designadas por & y && , respectivamente. En general, una referencia nos dice algo sobre la vida útil del objeto al que hace referencia, un puntero no. Comparar

void foo(int* i); void foo(int& i); void foo(int&& i);

En el primer caso, podría apuntar a un objeto que podemos asignar, pero lo más importante es que también puede ser nullptr o apuntar a uno más allá del final de una matriz. Por lo tanto, desreferenciarlo puede llevar a un comportamiento indefinido. La verificación de un nullptr es bastante fácil, la otra verificación no lo es.

El segundo y el tercer caso, siempre debo hacer referencia a un int válido que también podemos asignar.

La diferencia entre las referencias rvalue y rvalue es que las referencias rvalue/&& transmiten el significado de que nadie más necesita el valor de referencia y, como tal, permite optimizaciones. Lee sobre std::move y move constructors para ver a qué me refiero.

Para resumir: las referencias nos dicen algo sobre la vida útil del objeto. Claro, esto podría indicarse en la documentación, pero con indicaciones, las violaciones de ese contrato pueden ser difíciles de detectar. Las referencias hacen cumplir el contrato (en un alto grado) en el momento de la compilación y, como tal, proporcionan documentación al código de forma implícita. Esto permite algunas optimizaciones rápidas y sin complicaciones utilizando, por ejemplo, constructores de movimiento o reenvío perfecto en algunos casos.


Una variable de referencia no es más que un nombre de alias de la variable. Lo usaría cuando quisiera simplemente pasar el valor en lugar de copiar la misma variable en la memoria en una ubicación diferente. Por lo tanto, utilizando la referencia, se puede evitar la copia que guarda la memoria.

Según las preguntas frecuentes de Bjarne Stroustrup :

C ++ heredó los punteros de C, por lo que no pude eliminarlos sin causar problemas de compatibilidad graves. Las referencias son útiles para varias cosas, pero la razón directa por la que las introduje en C ++ fue para apoyar la sobrecarga del operador. Por ejemplo:

void f1(const complex* x, const complex* y) // without references { complex z = *x+*y; // ugly // ... } void f2(const complex& x, const complex& y) // with references { complex z = x+y; // better // ... }

De manera más general, si desea tener tanto la funcionalidad de los punteros como la funcionalidad de las referencias, necesita dos tipos diferentes (como en C ++) o dos conjuntos diferentes de operaciones en un solo tipo. Por ejemplo, con un solo tipo necesita tanto una operación para asignar al objeto al que se hace referencia como una operación para asignar a la referencia / puntero. Esto se puede hacer usando operadores separados (como en Simula). Por ejemplo:

Ref<My_type> r :- new My_type; r := 7; // assign to object r :- new My_type; // assign to reference

Alternativamente, podría confiar en la verificación de tipo (sobrecarga). Por ejemplo:

Ref<My_type> r = new My_type; r = 7; // assign to object r = new My_type; // assign to reference

Además, lea esta pregunta de Desbordamiento de pila sobre las diferencias entre una variable de puntero y una variable de referencia.