language-agnostic pass-by-reference pass-by-value

language agnostic - ¿Cuál es la diferencia entre pasar por referencia y pasar por valor?



language-agnostic pass-by-reference (17)

Antes de entender los 2 términos, DEBE comprender lo siguiente. Cada objeto, tiene 2 cosas que pueden distinguirlo.

  • Es valioso.
  • Su direccion

Así que si dices employee.name = "John"

Sepa que hay 2 cosas sobre el name . Su valor, que es "John" y también su ubicación en la memoria, que es un número hexadecimal, podría ser el siguiente: 0x7fd5d258dd00 .

Dependiendo de la arquitectura del idioma o del tipo (clase, estructura, etc.) de su objeto, estaría transfiriendo "John" o 0x7fd5d258dd00

Pasar "John" se conoce como pasar por valor. Pasar 0x7fd5d258dd00 se conoce como pasar por referencia. Cualquiera que apunte a esta ubicación de memoria tendrá acceso al valor de "John" .

Para más información sobre esto, le recomiendo que lea sobre la eliminación de referencias a un puntero y también por qué elegir la estructura (tipo de valor) sobre la clase (tipo de referencia)

Cuál es la diferencia entre

  1. un parámetro pasado por referencia
  2. un parámetro pasado por valor?

¿Podría darme algunos ejemplos, por favor?


Aquí hay un ejemplo que demuestra las diferencias entre la transferencia de valor por valor de puntero por referencia :

void swap_by_value(int a, int b){ int temp; temp = a; a = b; b = temp; } void swap_by_pointer(int *a, int *b){ int temp; temp = *a; *a = *b; *b = temp; } void swap_by_reference(int &a, int &b){ int temp; temp = a; a = b; b = temp; } int main(void){ int arg1 = 1, arg2 = 2; swap_by_value(arg1, arg2); cout << arg1 << " " << arg2 << endl; //prints 1 2 swap_by_pointer(&arg1, &arg2); cout << arg1 << " " << arg2 << endl; //prints 2 1 arg1 = 1; //reset values arg2 = 2; swap_by_reference(arg1, arg2); cout << arg1 << " " << arg2 << endl; //prints 2 1 }

El método de "pasar por referencia" tiene una limitación importante . Si un parámetro se declara como pasado por referencia (por lo que está precedido por el signo &), su parámetro real correspondiente debe ser una variable .

Un parámetro real que se refiere al parámetro formal "pasado por valor" puede ser una expresión en general, por lo que se le permite usar no solo una variable sino también un literal o incluso el resultado de una invocación de función.

La función no puede colocar un valor en otra cosa que no sea una variable. No puede asignar un nuevo valor a un literal o forzar una expresión para cambiar su resultado.

PD: También puede verificar la respuesta de Dylan Beattie en el hilo actual que lo explica en palabras sencillas.


Aquí hay un ejemplo:

#include <iostream> void by_val(int arg) { arg += 2; } void by_ref(int&arg) { arg += 2; } int main() { int x = 0; by_val(x); std::cout << x << std::endl; // prints 0 by_ref(x); std::cout << x << std::endl; // prints 2 int y = 0; by_ref(y); std::cout << y << std::endl; // prints 2 by_val(y); std::cout << y << std::endl; // prints 2 }


Comparando: Valor vs. Referencia

Pasar por valor Los parámetros locales son copias de los argumentos originales pasados ​​en Los cambios realizados en la función de estas variables no afectan a los originales

Pasar por referencia Los parámetros locales son referencias a las ubicaciones de almacenamiento de los argumentos originales pasados. Los cambios en estas variables en la función afectarán a los originales. No se realiza ninguna copia, por lo que se guarda la sobrecarga de copia (tiempo, almacenamiento)


Cuando se pasa por ref, básicamente se pasa un puntero a la variable. Pasa por valor estás pasando una copia de la variable. En el uso básico, esto normalmente significa que los cambios pasados ​​por ref a la variable se verán como el método de llamada y pasarán por el valor que no.


Ejemplos:

class Dog { public: barkAt( const std::string& pOtherDog ); // const reference barkAt( std::string pOtherDog ); // value };

const & es generalmente mejor. Usted no incurre en la pena de construcción y destrucción. Si la referencia no es constante, su interfaz sugiere que cambiará la información pasada.


En primer lugar, la distinción "pasar por valor frente a pasar por referencia", tal como se define en la teoría CS, ahora es obsoleta porque la técnica originalmente definida como "pasar por referencia" ha perdido popularidad y rara vez se usa ahora. 1

Los lenguajes más nuevos 2 tienden a usar un par de técnicas diferentes (pero similares) para lograr los mismos efectos (ver más abajo), que es la principal fuente de confusión.

Una fuente secundaria de confusión es el hecho de que en "pasar por referencia", "referencia" tiene un significado más estrecho que el término general "referencia" (porque la frase es anterior).

Ahora, la definición auténtica es:

  • Cuando se pasa un parámetro por referencia , la persona que llama y la persona que llama utilizan la misma variable para el parámetro. Si la persona que llama modifica la variable del parámetro, el efecto es visible para la variable de la persona que llama.

  • Cuando se pasa un parámetro por valor , el llamante y el destinatario tienen dos variables independientes con el mismo valor. Si la persona que llama modifica la variable del parámetro, el efecto no es visible para la persona que llama.

Las cosas a tener en cuenta en esta definición son:

  • "Variable" aquí significa la variable de la persona que llama (local o global) , es decir, si paso una variable local por referencia y le asigno, cambiaré la variable de la persona que llama, no la que apunta a un puntero .

    • Esto ahora se considera una mala práctica (como una dependencia implícita). Como tal, prácticamente todos los idiomas nuevos son exclusiva o casi exclusivamente pasados ​​por valor. El paso por referencia ahora se usa principalmente en forma de "argumentos de salida / entrada" en idiomas donde una función no puede devolver más de un valor.
  • El significado de "referencia" en "pasar por referencia" . La diferencia con el término general de "referencia" es que esta "referencia" es temporal e implícita. Lo que la persona que recibe básicamente recibe es una "variable" que de alguna manera es "la misma" que la original. El hecho de que se logre específicamente este efecto es irrelevante (por ejemplo, el lenguaje también puede exponer algunos detalles de la implementación: direcciones, punteros, desreferencias, todo esto es irrelevante; si el efecto neto es este, es el paso por referencia).

Ahora, en los lenguajes modernos, las variables tienden a ser de "tipos de referencia" (otro concepto inventado más tarde que "pasar por referencia" e inspirado en él), es decir, los datos reales del objeto se almacenan por separado en algún lugar (generalmente, en el montón), y solo las "referencias" a él se mantienen en variables y se pasan como parámetros. 3

Al pasar una referencia de este tipo, se pasa por debajo del valor porque el valor de una variable es técnicamente la referencia en sí, no el objeto referido. Sin embargo, el efecto neto en el programa puede ser el mismo que pase por valor o paso por referencia:

  • Si solo se toma una referencia de la variable de un llamador y se pasa como un argumento, esto tiene el mismo efecto que el paso por referencia: si el objeto referido está mutado en el destinatario, el llamante verá el cambio.
    • Sin embargo, si una variable que contiene esta referencia se reasigna, dejará de apuntar a ese objeto, por lo que cualquier otra operación en esta variable afectará a lo que apunta ahora.
  • Para tener el mismo efecto que el paso por valor, se realiza una copia del objeto en algún momento. Las opciones incluyen:
    • La persona que llama solo puede hacer una copia privada antes de la llamada y darle a la persona que llama una referencia a eso en su lugar.
    • En algunos idiomas, algunos tipos de objetos son "inmutables": cualquier operación en ellos que parece alterar el valor en realidad crea un objeto completamente nuevo sin afectar al original. Por lo tanto, pasar un objeto de tal tipo como argumento siempre tiene el efecto de pasar por un valor: una copia para el destinatario se realizará automáticamente siempre y cuando necesite un cambio, y el objeto de la persona que llama nunca se verá afectado.
      • En los lenguajes funcionales, todos los objetos son inmutables.

Como puede ver, este par de técnicas es casi igual a las de la definición, solo con un nivel de direccionamiento indirecto: simplemente reemplace "variable" con "objeto referenciado".

No hay un nombre acordado para ellos, lo que lleva a explicaciones distorsionadas como "llamada por valor donde el valor es una referencia". En 1975, Barbara Liskov sugirió el término " call-by-object-sharing " (o algunas veces simplemente "llamada por compartir"), aunque nunca se dio cuenta. Además, ninguna de estas frases dibuja un paralelo con el par original. No es de extrañar que los viejos términos terminen siendo reutilizados en ausencia de algo mejor, lo que lleva a la confusión. 4

NOTA : Durante mucho tiempo, esta respuesta solía decir:

Di que quiero compartir una página web contigo. Si te digo la URL, la paso por referencia. Puedes usar esa URL para ver la misma página web que puedo ver. Si se cambia esa página, ambos veremos los cambios. Si elimina la URL, todo lo que está haciendo es destruir su referencia a esa página, no está eliminando la página en sí.

Si imprimo la página y le entrego la copia impresa, lo pasaré por valor. Su página es una copia desconectada del original. No verá ningún cambio posterior, y los cambios que realice (por ejemplo, al escribir en su copia impresa) no se mostrarán en la página original. Si destruye la copia impresa, en realidad ha destruido su copia del objeto, pero la página web original permanece intacta.

Esto es correcto en su mayor parte, excepto el significado más estrecho de "referencia": es temporal e implícito (no tiene por qué serlo, pero al ser explícito y / o persistente son características adicionales, no una parte de la semántica de paso por referencia) , como se explicó anteriormente). Una analogía más cercana sería darle una copia de un documento frente a invitarlo a trabajar en el original.

1 A menos que esté programando en Fortran o Visual Basic, no es el comportamiento predeterminado, y en la mayoría de los lenguajes de uso moderno, la verdadera llamada por referencia no es posible.

2 Una buena cantidad de los mayores lo apoyan, también

3 En varios idiomas modernos, todos los tipos son tipos de referencia. Este enfoque fue iniciado por el lenguaje CLU en 1975 y desde entonces ha sido adoptado por muchos otros idiomas, incluidos Python y Ruby. Y muchos más lenguajes utilizan un enfoque híbrido, donde algunos tipos son "tipos de valor" y otros son "tipos de referencia", entre ellos, C #, Java y JavaScript.

4 No hay nada malo en reciclar un término antiguo apropiado per se, pero uno tiene que dejar en claro qué significado se usa cada vez. No hacerlo es exactamente lo que sigue causando confusión.


En resumen, Pasado por valor es lo que es y pasado por referencia es donde está.

Si su valor es VAR1 = "¡Chico feliz!", Solo verá "¡Chico feliz!". Si VAR1 cambia a "Happy Gal!", No lo sabrás. Si se pasa por referencia, y VAR1 cambia, lo harás.


Es una forma de pasar argumentos a las funciones. Pasar por referencia significa que el parámetro de las funciones llamadas será el mismo que el argumento pasado por los llamadores (no el valor, sino la identidad, la variable en sí). Pasar por valor significa que el parámetro de las funciones llamadas será una copia del argumento pasado de los llamadores. El valor será el mismo, pero la identidad, la variable, es diferente. Por lo tanto, los cambios en un parámetro realizado por la función llamada en un caso cambian el argumento pasado y en el otro caso solo cambian el valor del parámetro en la función llamada (que es solo una copia). En un apuro rápido:

  • Java solo soporta pasar por valor. Siempre copia los argumentos, aunque al copiar una referencia a un objeto, el parámetro en la función llamada apuntará al mismo objeto y los cambios en ese objeto se verán en la persona que llama. Como esto puede ser confuso, here es lo que Jon Skeet tiene que decir al respecto.
  • C # admite el paso por valor y el paso por referencia (referencia de palabra clave utilizada en el llamador y la función llamada). Jon Skeet también tiene una buena explicación de esto here .
  • C ++ admite el paso por valor y el paso por referencia (tipo de parámetro de referencia utilizado en la función llamada). Encontrarás una explicación de esto a continuación.

Codigos

Ya que mi lenguaje es C ++, lo usaré aquí

// passes a pointer (called reference in java) to an integer void call_by_value(int *p) { // :1 p = NULL; } // passes an integer void call_by_value(int p) { // :2 p = 42; } // passes an integer by reference void call_by_reference(int & p) { // :3 p = 42; } // this is the java style of passing references. NULL is called "null" there. void call_by_value_special(int *p) { // :4 *p = 10; // changes what p points to ("what p references" in java) // only changes the value of the parameter, but *not* of // the argument passed by the caller. thus it''s pass-by-value: p = NULL; } int main() { int value = 10; int * pointer = &value; call_by_value(pointer); // :1 assert(pointer == &value); // pointer was copied call_by_value(value); // :2 assert(value == 10); // value was copied call_by_reference(value); // :3 assert(value == 42); // value was passed by reference call_by_value_special(pointer); // :4 // pointer was copied but what pointer references was changed. assert(value == 10 && pointer == &value); }

Y un ejemplo en Java no hará daño:

class Example { int value = 0; // similar to :4 case in the c++ example static void accept_reference(Example e) { // :1 e.value++; // will change the referenced object e = null; // will only change the parameter } // similar to the :2 case in the c++ example static void accept_primitive(int v) { // :2 v++; // will only change the parameter } public static void main(String... args) { int value = 0; Example ref = new Example(); // reference // note what we pass is the reference, not the object. we can''t // pass objects. The reference is copied (pass-by-value). accept_reference(ref); // :1 assert ref != null && ref.value == 1; // the primitive int variable is copied accept_primitive(value); // :2 assert value == 0; } }

Wikipedia

http://en.wikipedia.org/wiki/Pass_by_reference#Call_by_value

http://en.wikipedia.org/wiki/Pass_by_reference#Call_by_reference

Este tipo casi lo clava:

http://javadude.com/articles/passbyvalue.htm


La forma más sencilla de obtener esto es en un archivo de Excel. Digamos, por ejemplo, que tienes dos números, 5 y 2 en las celdas A1 y B1 en consecuencia, y quieres encontrar su suma en una tercera celda, digamos A2. Puede hacer esto de dos maneras.

  • O bien pasando sus valores a la celda A2 escribiendo = 5 + 2 en esta celda. En este caso, si los valores de las celdas A1 o B1 cambian, la suma en A2 permanece igual.

  • O pasando las "referencias" de las celdas A1 y B1 a la celda A2 escribiendo = A1 + B1 . En este caso, si los valores de las celdas A1 o B1 cambian, la suma en A2 también cambia.


Muchas respuestas aquí (y, en particular, las respuestas más elevadas) son objetivamente incorrectas, ya que malinterpretan lo que realmente significa "llamada por referencia". Aquí está mi intento de aclarar las cosas.

TL; DR

En los términos más simples:

  • llamada por valor significa que pasas valores como argumentos de función
  • llamar por referencia significa que pasas variables como argumentos de función

En términos metafóricos:

  • Llamar por valor es donde escribo algo en un papel y se lo entrego . Tal vez sea una URL, tal vez sea una copia completa de Guerra y Paz. No importa lo que sea, está en un trozo de papel que te he entregado, y ahora es efectivamente tu trozo de papel . Ahora eres libre de garabatear en ese trozo de papel, o usar ese trozo de papel para encontrar algo en otro lugar y jugar con él, lo que sea.
  • Llamar por referencia es cuando te entrego mi cuaderno que tiene algo escrito en él . Puedes garabatear en mi cuaderno (tal vez quiero que lo hagas, tal vez no), y luego guardo mi cuaderno, con cualquier garabato que hayas puesto allí. Además, si lo que usted o yo escribimos hay información sobre cómo encontrar algo en otra parte, usted o yo podemos ir allí y jugar con esa información.

Lo que "llamada por valor" y "llamada por referencia" no significan

Tenga en cuenta que ambos conceptos son completamente independientes y ortogonales del concepto de tipos de referencia (que en Java son todos los tipos que son subtipos de Object y en C # todos class tipos de class ), o el concepto de tipos de punteros como en C (que son semánticamente equivalente a los "tipos de referencia" de Java, simplemente con una sintaxis diferente).

La noción de tipo de referencia corresponde a una URL: es en sí misma una parte de información y es una referencia (un puntero , si lo desea) a otra información. Puede tener muchas copias de una URL en diferentes lugares, y no cambian el sitio web al que están vinculados; Si se actualiza el sitio web, cada copia de URL seguirá llevando a la información actualizada. Por el contrario, cambiar la URL en cualquier lugar no afectará a ninguna otra copia escrita de la URL.

Tenga en cuenta que C ++ tiene una noción de "referencias" (por ejemplo, int& ) que no es como los "tipos de referencia" de Java y C #, sino que es como "llamada por referencia". Los "tipos de referencia" de Java y C #, y todos los tipos en Python, son como lo que C y C ++ llaman "tipos de puntero" (por ejemplo, int* ).

OK, aquí está la explicación más larga y más formal.

Terminología

Para empezar, quiero resaltar algunos aspectos importantes de la terminología, para ayudar a aclarar mi respuesta y asegurarnos de que todos nos estamos refiriendo a las mismas ideas cuando estamos usando palabras. (En la práctica, creo que la gran mayoría de la confusión sobre temas como estos se deriva del uso de palabras para no comunicar completamente el significado que se pretendía).

Para empezar, aquí hay un ejemplo en algún lenguaje tipo C de una declaración de función:

void foo(int param) { // line 1 param += 1; }

Y aquí hay un ejemplo de llamar a esta función:

void bar() { int arg = 1; // line 2 foo(arg); // line 3 }

Usando este ejemplo, quiero definir algunos bits importantes de terminología:

  • foo es una función declarada en la línea 1 (Java insiste en hacer todos los métodos de funciones, pero el concepto es el mismo sin pérdida de generalidad; C y C ++ hacen una distinción entre declaración y definición a la que no voy a entrar aquí)
  • param es un parámetro formal para foo , también declarado en la línea 1
  • arg es una variable , específicamente una variable local de la bar funciones, declarada e inicializada en la línea 2
  • arg también es un argumento para una invocación específica de foo en la línea 3

Hay dos conjuntos muy importantes de conceptos para distinguir aquí. El primero es valor versus variable :

  • Un valor es el resultado de evaluar una expresión en el lenguaje. Por ejemplo, en la función de bar anterior, después de la línea int arg = 1; , la expresión arg tiene el valor 1 .
  • Una variable es un contenedor de valores . Una variable puede ser mutable (este es el valor predeterminado en la mayoría de los lenguajes similares a C), de solo lectura (p. Ej., Declarada usando la versión final de Java o C # de readonly ) o profundamente inmutable (p. Ej. Utilizando la const C ++).

El otro par importante de conceptos para distinguir es parámetro versus argumento :

  • Un parámetro (también llamado parámetro formal ) es una variable que debe ser proporcionada por la persona que llama cuando llama a una función.
  • Un argumento es un valor que proporciona el llamador de una función para satisfacer un parámetro formal específico de esa función

Llamar por valor

En la llamada por valor , los parámetros formales de la función son variables que se crean recientemente para la invocación de la función y que se inicializan con los valores de sus argumentos.

Esto funciona exactamente de la misma manera que cualquier otro tipo de variables se inicializan con valores. Por ejemplo:

int arg = 1; int another_variable = arg;

Aquí arg y another_variable son variables completamente independientes, sus valores pueden cambiar independientemente entre sí. Sin embargo, en el punto donde se declara another_variable , se inicializa para mantener el mismo valor que arg mantiene, que es 1 .

Dado que son variables independientes, los cambios en otra another_variable no afectan a arg :

int arg = 1; int another_variable = arg; another_variable = 2; assert arg == 1; // true assert another_variable == 2; // true

Esto es exactamente igual a la relación entre arg y param en nuestro ejemplo anterior, que repetiré aquí para la simetría:

void foo(int param) { param += 1; } void bar() { int arg = 1; foo(arg); }

Es exactamente como si hubiéramos escrito el código de esta manera:

// entering function "bar" here int arg = 1; // entering function "foo" here int param = arg; param += 1; // exiting function "foo" here // exiting function "bar" here

Es decir, la característica definitoria de lo que significa call by value es que la persona que llama ( foo en este caso) recibe valores como argumentos, pero tiene sus propias variables separadas para esos valores de las variables de la persona que llama ( bar en este caso).

Volviendo a mi metáfora de arriba, si soy un bar y tú eres muy bueno, cuando te llamo, te entrego un pedazo de papel con un valor escrito en él. Usted llama a ese pedazo de papel param . Ese valor es una copia del valor que he escrito en mi cuaderno (mis variables locales), en una variable que llamo arg .

(Aparte de esto: según el hardware y el sistema operativo, existen varias convenciones de llamada sobre cómo llamar a una función desde otra. La convención de llamada es como si decidiéramos si escribo el valor en un pedazo de mi papel y luego se lo entrego a usted , o si tiene un papel en el que lo escribo, o si lo escribo en la pared frente a los dos. Este es un tema interesante también, pero mucho más allá del alcance de esta respuesta larga.

Llamar por referencia

En la llamada por referencia , los parámetros formales de la función son simplemente nombres nuevos para las mismas variables que la persona que llama proporciona como argumentos.

Volviendo a nuestro ejemplo anterior, es equivalente a:

// entering function "bar" here int arg = 1; // entering function "foo" here // aha! I note that "param" is just another name for "arg" arg /* param */ += 1; // exiting function "foo" here // exiting function "bar" here

Dado que param es solo otro nombre para arg , es decir, son la misma variable , los cambios a param se reflejan en arg . Esta es la forma fundamental en que la llamada por referencia difiere de la llamada por valor.

Muy pocos idiomas admiten llamadas por referencia, pero C ++ puede hacerlo de esta manera:

void foo(int& param) { param += 1; } void bar() { int arg = 1; foo(arg); }

En este caso, param no solo tiene el mismo valor que arg , en realidad es arg (solo por un nombre diferente) y, por lo tanto, bar puede observar que se ha incrementado arg .

Tenga en cuenta que no es así como funciona hoy en día cualquiera de Java, JavaScript, C, Objective-C, Python o casi cualquier otro lenguaje popular. Esto significa que esos idiomas no son llamados por referencia, son llamados por valor.

Anexo: llamada por compartir objeto

Si lo que tiene es llamada por valor , pero el valor real es un tipo de referencia o tipo de puntero , entonces el "valor" en sí no es muy interesante (por ejemplo, en C es solo un número entero de un tamaño específico de la plataforma). Interesante es a lo que apunta ese valor.

Si lo que señala ese tipo de referencia (es decir, el puntero) es mutable, entonces es posible un efecto interesante: puede modificar el valor apuntado a, y la persona que llama puede observar los cambios en el valor apuntado a, aunque la persona que llama no puede observar Cambia al puntero en sí.

Para volver a tomar prestada la analogía de la URL, el hecho de que le haya dado una copia de la URL a un sitio web no es particularmente interesante si lo que a ambos nos importa es el sitio web, no la URL. El hecho de que garabatee sobre su copia de la URL no afecta a mi copia de la URL no es algo que nos importe (y de hecho, en idiomas como Java y Python, la "URL", o valor de tipo de referencia, puede no se modifica en absoluto, solo la cosa apuntada por ella puede).

Barbara Liskov, cuando inventó el lenguaje de programación CLU (que tenía estas semánticas), se dio cuenta de que los términos existentes "llamada por valor" y "llamada por referencia" no eran particularmente útiles para describir la semántica de este nuevo idioma. Así que ella inventó un nuevo término: call-by-object-sharing .

Cuando se habla de lenguajes que son técnicamente llamados por valor, pero donde los tipos comunes en uso son los tipos de referencia o de puntero (es decir, casi todos los imperativos modernos, orientados a objetos o lenguaje de programación de múltiples paradigmas), me parece mucho menos confuso simplemente evite hablar de llamada por valor o llamada por referencia . Quédate para llamar por compartir objetos (o simplemente llamar por objeto ) y nadie se confundirá. :-)


Pasar por valor envía una COPIA de los datos almacenados en la variable que especifique, pasar por referencia envía un enlace directo a la variable en sí. Entonces, si pasa una variable por referencia y luego cambia la variable dentro del bloque al que la pasó, la variable original cambiará. Si simplemente pasa por valor, la variable original no podrá ser cambiada por el bloque al que la pasó, pero obtendrá una copia de lo que contenía en el momento de la llamada.


Pasar por valor: la función copia la variable y trabaja con una copia (para que no cambie nada en la variable original)

Pasar por referencia: la función utiliza la variable original; si cambia la variable en la otra función, también cambia la variable original.

Ejemplo (copie y use / intente esto usted mismo y vea):

#include <iostream> using namespace std; void funct1(int a){ //pass-by-value a = 6; //now "a" is 6 only in funct1, but not in main or anywhere else } void funct2(int &a){ //pass-by-reference a = 7; //now "a" is 7 both in funct2, main and everywhere else it''ll be used } int main() { int a = 5; funct1(a); cout<<endl<<"A is currently "<<a<<endl<<endl; //will output 5 funct2(a); cout<<endl<<"A is currently "<<a<<endl<<endl; //will output 7 return 0; }

Mantenlo simple, píos. Las paredes de texto pueden ser un mal hábito.


Por definición, pasar por valor significa que está haciendo una copia en la memoria del valor del parámetro real que se pasa, una copia del contenido del parámetro real. Use el paso por valor cuando solo esté "usando" el parámetro para algunos cálculos, no lo cambie por el programa cliente.

En paso por referencia (también llamado paso por dirección), se almacena una copia de la dirección del parámetro real. Use paso por referencia cuando esté cambiando el parámetro pasado por el programa cliente.


Si no desea cambiar el valor de la variable original después de pasarla a una función, la función debe construirse con un parámetro " pasar por valor ".

Entonces la función tendrá SOLAMENTE el valor pero no la dirección de la variable pasada. Sin la dirección de la variable, el código dentro de la función no puede cambiar el valor de la variable como se ve desde el exterior de la función.

Pero si desea otorgar a la función * la capacidad de cambiar el valor de la variable como se ve desde el exterior, debe usar el paso por referencia . Dado que tanto el valor como la dirección (referencia) se pasan y están disponibles dentro de la función.


Una diferencia importante entre ellas es que las variables de tipo valor almacenan valores, por lo que la especificación de una variable de tipo valor en una llamada de método pasa una copia del valor de esa variable al método. Las variables de tipo de referencia almacenan referencias a objetos, por lo que al especificar una variable de tipo de referencia como argumento, se pasa al método una copia de la referencia real que se refiere al objeto. Aunque la referencia en sí misma se pasa por valor, el método puede seguir utilizando la referencia que recibe para interactuar con, y posiblemente modificar, el objeto original. De manera similar, cuando se devuelve información de un método a través de una declaración de retorno, el método devuelve una copia del valor almacenado en una variable de tipo de valor o una copia de la referencia almacenada en una variable de tipo de referencia. Cuando se devuelve una referencia, el método de llamada puede usar esa referencia para interactuar con el objeto al que se hace referencia. Entonces, en efecto, los objetos siempre se pasan por referencia.

En c #, para pasar una variable por referencia para que el método llamado pueda modificar la variable, C # proporciona palabras clave ref y out. La aplicación de la palabra clave ref a una declaración de parámetro le permite pasar una variable a un método por referencia, el método llamado podrá modificar la variable original en el llamador. La palabra clave ref se utiliza para las variables que ya se han inicializado en el método de llamada. Normalmente, cuando una llamada de método contiene una variable sin inicializar como argumento, el compilador genera un error. Antes de un parámetro con una palabra clave fuera crea un parámetro de salida. Esto indica al compilador que el argumento se pasará al método llamado por referencia y que el método llamado asignará un valor a la variable original en el llamador. Si el método no asigna un valor al parámetro de salida en cada ruta posible de ejecución, el compilador genera un error. Esto también evita que el compilador genere un mensaje de error para una variable no inicializada que se pasa como un argumento a un método. Un método puede devolver solo un valor a su interlocutor a través de una declaración de retorno, pero puede devolver muchos valores especificando múltiples parámetros de salida (referencia y / o salida).

ver c # discusión y ejemplos aquí enlace texto


pasar por valor significa cómo pasar valor a una función haciendo uso de argumentos. en paso por valor, copiamos los datos almacenados en la variable que especificamos y es más lento que pasar por referencia porque los datos se copian. De hacer cambios en los datos copiados, los datos originales no se ven afectados. En caso de pasar por referencia o por dirección, enviamos un enlace directo a la variable en sí. o pasar el puntero a una variable. Es más rápido porque se consume menos tiempo.