valores una tipos retornan que programacion parametros funciones funcion estructura ejemplos dev con c++ pointers pass-by-reference pass-by-value c++-faq

c++ - una - tipos de funciones en c



¿Cómo pasar objetos a funciones en C++? (7)

Reglas generales para C ++ 11:

Pase por valor , excepto cuando

  1. no necesita la propiedad del objeto y un simple alias lo hará, en cuyo caso se pasa por referencia const ,
  2. debe mutar el objeto, en cuyo caso, use pass por una referencia de valor no const ,
  3. pasa objetos de clases derivadas como clases base, en cuyo caso necesita pasar por referencia . (Utilice las reglas anteriores para determinar si se debe pasar por referencia const o no).

Pasar por el puntero prácticamente nunca se aconseja. Los parámetros opcionales se expresan mejor como un boost::optional , y el aliasing se hace bien por referencia.

La semántica de movimientos de C ++ 11 hace que pasar y regresar por valor sea mucho más atractivo incluso para objetos complejos.

Reglas generales para C ++ 03:

Pasar argumentos por referencia const , excepto cuando

  1. deben cambiarse dentro de la función y dichos cambios deben reflejarse en el exterior, en cuyo caso se pasa por referencia no const
  2. la función debe ser invocable sin ningún argumento, en cuyo caso se pasa por un puntero, para que los usuarios puedan pasar NULL / 0 / nullptr lugar; aplique la regla anterior para determinar si debe pasar un puntero a un argumento const
  3. Son de tipos incorporados, que pueden pasarse por copia.
  4. deben cambiarse dentro de la función y dichos cambios no deben reflejarse afuera, en cuyo caso puede pasar por copia (una alternativa sería pasar según las reglas anteriores y hacer una copia dentro de la función)

(aquí, "pasar por valor" se llama "pasar por copia", porque pasar por valor siempre crea una copia en C ++ 03)

Hay más en esto, pero estas reglas para principiantes te llevarán bastante lejos.

Soy nuevo en la programación de C ++, pero tengo experiencia en Java. Necesito orientación sobre cómo pasar objetos a funciones en C ++.

¿Debo pasar punteros, referencias o valores que no sean de puntero y no de referencia? Recuerdo que en Java no existen tales problemas, ya que solo pasamos la variable que contiene la referencia a los objetos.

Sería genial si también pudiera explicar dónde usar cada una de esas opciones.


Pase por valor:

void func (vector v)

Pase las variables por valor cuando la función necesite un aislamiento completo del entorno, es decir, para evitar que la función modifique la variable original, así como para evitar que otros subprocesos modifiquen su valor mientras se ejecuta la función.

El inconveniente son los ciclos de la CPU y la memoria extra que se utiliza para copiar el objeto.

Pase por referencia const:

void func (const vector & v);

Este formulario emula el comportamiento de paso por valor al tiempo que elimina la sobrecarga de copia. La función obtiene acceso de lectura al objeto original, pero no puede modificar su valor.

La desventaja es la seguridad del hilo: cualquier cambio realizado en el objeto original por otro hilo aparecerá dentro de la función mientras aún se está ejecutando.

Pase por referencia no const:

void func (vector & v)

Use esto cuando la función tenga que escribir algo de valor en la variable, que finalmente será utilizada por la persona que llama.

Al igual que en el caso de referencia de const, esto no es seguro para subprocesos.

Pase por el puntero const:

void func (const vector * vp);

Funcionalmente igual a pasar por const-reference excepto por la diferente sintaxis, más el hecho de que la función de llamada puede pasar el puntero NULL para indicar que no tiene datos válidos para pasar.

No hilo seguro.

Pasar por puntero no const:

void func (vector * vp);

Similar a la referencia no const. La persona que llama normalmente establece la variable en NULL cuando se supone que la función no debe escribir un valor. Esta convención se ve en muchas API de glibc. Ejemplo:

void func (string * str, /* ... */) { if (str != NULL) { *str = some_value; // assign to *str only if it''s non-null } }

Al igual que todos pasan por referencia / puntero, no es seguro para subprocesos.


Dado que nadie menciona lo estoy agregando, cuando se pasa un objeto a una función en c ++, se llama al constructor de copia predeterminado del objeto si no tiene uno que cree un clon del objeto y luego lo pase al método, por lo que cuando se cambian los valores del objeto que se reflejarán en la copia del objeto en lugar del objeto original, ese es el problema en c ++. Entonces, si hace que todos los atributos de clase sean punteros, los constructores de la copia copiarán las direcciones de los atributos del puntero, por lo que cuando el método invoca el objeto que manipula los valores almacenados en las direcciones de los atributos del puntero, los cambios también se reflejan en el objeto original que se pasa como parámetro, por lo que este puede comportarse como un Java pero no olvide que toda su clase Los atributos deben ser punteros, también debe cambiar los valores de los punteros, será mucho más claro con la explicación del código.

Class CPlusPlusJavaFunctionality { public: CPlusPlusJavaFunctionality(){ attribute = new int; *attribute = value; } void setValue(int value){ *attribute = value; } void getValue(){ return *attribute; } ~ CPlusPlusJavaFuncitonality(){ delete(attribute); } private: int *attribute; } void changeObjectAttribute(CPlusPlusJavaFunctionality obj, int value){ int* prt = obj.attribute; *ptr = value; } int main(){ CPlusPlusJavaFunctionality obj; obj.setValue(10); cout<< obj.getValue(); //output: 10 changeObjectAttribute(obj, 15); cout<< obj.getValue(); //output: 15 }

Pero esto no es una buena idea, ya que terminará de escribir muchos códigos relacionados con punteros, que son propensos a las fugas de memoria y no se olvidan de llamar a los destructores. Y para evitar esto, c ++ tiene constructores de copia donde creará nueva memoria cuando los objetos que contienen punteros se pasen a argumentos de función que dejarán de manipular otros datos de objetos, Java pasa por valor y el valor es referencia, por lo que no requiere que los constructores de copia.


Hay algunas diferencias en las convenciones de llamada en C ++ y Java. En C ++, técnicamente, solo existen dos convenciones: paso por valor y paso por referencia, y algunos textos incluyen un tercer convenio paso por puntero (que en realidad es un tipo de puntero de paso por valor). Además de eso, puede agregar constancia al tipo de argumento, mejorando la semántica.

Pasar por referencia

Pasar por referencia significa que la función recibirá conceptualmente su instancia de objeto y no una copia de ella. Conceptualmente, la referencia es un alias al objeto que se usó en el contexto de la llamada y no puede ser nulo. Todas las operaciones realizadas dentro de la función se aplican al objeto fuera de la función. Esta convención no está disponible en Java o C.

Pase por valor (y paso por puntero)

El compilador generará una copia del objeto en el contexto de la llamada y usará esa copia dentro de la función. Todas las operaciones realizadas dentro de la función se realizan en la copia, no en el elemento externo. Esta es la convención para los tipos primitivos en Java.

Una versión especial del mismo es pasar un puntero (dirección del objeto) a una función. La función recibe el puntero, y cualquiera y todas las operaciones aplicadas al puntero mismo se aplican a la copia (puntero), por otra parte, las operaciones aplicadas al puntero sin referencia se aplicarán a la instancia del objeto en esa ubicación de memoria, por lo que la función Puede tener efectos secundarios. El efecto de usar el puntero de un puntero al objeto permitirá que la función interna modifique los valores externos, al igual que con el paso por referencia, y también permitirá valores opcionales (pase un puntero nulo).

Esta es la convención utilizada en C cuando una función necesita modificar una variable externa, y la convención utilizada en Java con tipos de referencia: la referencia se copia, pero el objeto referido es el mismo: los cambios en la referencia / puntero no son visibles afuera La función, pero los cambios en la memoria apuntada son.

Sumando const a la ecuación

En C ++ puede asignar una constante a los objetos al definir variables, punteros y referencias en diferentes niveles. Puede declarar que una variable es constante, puede declarar una referencia a una instancia constante, y puede definir todos los punteros a objetos constantes, punteros constantes a objetos mutables y punteros constantes a elementos constantes. A la inversa, en Java solo puede definir un nivel de constante (palabra clave final): el de la variable (instancia para tipos primitivos, referencia para tipos de referencia), pero no puede definir una referencia a un elemento inmutable (a menos que la clase en sí sea inmutable).

Esto se usa ampliamente en las convenciones de llamada de C ++. Cuando los objetos son pequeños puedes pasar el objeto por valor. El compilador generará una copia, pero esa copia no es una operación costosa. Para cualquier otro tipo, si la función no cambia el objeto, puede pasar una referencia a una instancia constante (generalmente llamada referencia constante) del tipo. Esto no copiará el objeto, sino que lo pasará a la función. Pero al mismo tiempo, el compilador garantizará que el objeto no se modifique dentro de la función.

Reglas de juego

Estas son algunas reglas básicas a seguir:

  • Prefiero pasar por valor para tipos primitivos
  • Prefiere paso por referencia con referencias a constante para otros tipos
  • Si la función necesita modificar el argumento use paso por referencia
  • Si el argumento es opcional, use el puntero paso a paso (a constante si no se debe modificar el valor opcional)

Existen otras pequeñas desviaciones de estas reglas, la primera de las cuales es el manejo de la propiedad de un objeto. Cuando un objeto se asigna dinámicamente con nuevo, debe ser desasignado con eliminar (o las versiones [] del mismo). El objeto o función que es responsable de la destrucción del objeto se considera el propietario del recurso. Cuando un objeto asignado dinámicamente se crea en un fragmento de código, pero la propiedad se transfiere a un elemento diferente, generalmente se realiza con semántica de paso por puntero o, si es posible, con punteros inteligentes.

Nota al margen

Es importante insistir en la importancia de la diferencia entre las referencias de C ++ y Java. En C ++, las referencias son conceptualmente la instancia del objeto, no un elemento de acceso a él. El ejemplo más simple es implementar una función de intercambio:

// C++ class Type; // defined somewhere before, with the appropriate operations void swap( Type & a, Type & b ) { Type tmp = a; a = b; b = tmp; } int main() { Type a, b; Type old_a = a, old_b = b; swap( a, b ); assert( a == old_b ); assert( b == old_a ); }

La función de intercambio anterior cambia ambos argumentos a través del uso de referencias. El código más cercano en Java:

public class C { // ... public static void swap( C a, C b ) { C tmp = a; a = b; b = tmp; } public static void main( String args[] ) { C a = new C(); C b = new C(); C old_a = a; C old_b = b; swap( a, b ); // a and b remain unchanged a==old_a, and b==old_b } }

La versión de Java del código modificará las copias de las referencias internamente, pero no modificará los objetos reales externamente. Las referencias de Java son punteros C sin aritmética de punteros que pasan de valor a funciones.


Hay tres métodos para pasar un objeto a una función como parámetro:

  1. Pasar por referencia
  2. pasar por valor
  3. añadiendo constante en el parámetro

Ir a través del siguiente ejemplo:

class Sample { public: int *ptr; int mVar; Sample(int i) { mVar = 4; ptr = new int(i); } ~Sample() { delete ptr; } void PrintVal() { cout << "The value of the pointer is " << *ptr << endl << "The value of the variable is " << mVar; } }; void SomeFunc(Sample x) { cout << "Say i am in someFunc " << endl; } int main() { Sample s1= 10; SomeFunc(s1); s1.PrintVal(); char ch; cin >> ch; }

Salida:

Di que estoy en algun funcion
El valor del puntero es -17891602.
El valor de la variable es 4.


Hay varios casos a considerar.

Parámetro modificado (parámetros "out" y "in / out")

void modifies(T &param); // vs void modifies(T *param);

Este caso es principalmente sobre estilo: ¿quieres que el código se vea como llamada (obj) o llamada (& obj) ? Sin embargo, hay dos puntos en los que la diferencia es importante: el caso opcional, a continuación, y desea utilizar una referencia cuando sobrecargue a los operadores.

... y opcional

void modifies(T *param=0); // default value optional, too // vs void modifies(); void modifies(T &param);

Parámetro no modificado

void uses(T const &param); // vs void uses(T param);

Este es el caso interesante. La regla de oro es que los tipos "baratos para copiar" se pasan por valor, generalmente son tipos pequeños (pero no siempre), mientras que otros se pasan por const. Ref. Sin embargo, si necesita hacer una copia dentro de su función independientemente, debe pasar por valor . (Sí, esto expone un poco de detalles de implementación. C''est le C ++. )

... y opcional

void uses(T const *param=0); // default value optional, too // vs void uses(); void uses(T const &param); // or optional(T param)

Aquí hay la menor diferencia entre todas las situaciones, así que elija la que le haga la vida más fácil.

Const por valor es un detalle de implementación

void f(T); void f(T const);

¡Estas declaraciones son en realidad exactamente la misma función! Cuando se pasa por valor, const es puramente un detalle de implementación. Pruébalo:

void f(int); void f(int const) { /* implements above function, not an overload */ } typedef void NC(int); // typedefing function types typedef void C(int const); NC *nc = &f; // nc is a function pointer C *c = nc; // C and NC are identical types


Las siguientes son las formas de pasar argumentos / parámetros para funcionar en C ++.

1. por valor.

// passing parameters by value . . . void foo(int x) { x = 6; }

2. por referencia.

// passing parameters by reference . . . void foo(const int &x) // x is a const reference { x = 6; } // passing parameters by const reference . . . void foo(const int &x) // x is a const reference { x = 6; // compile error: a const reference cannot have its value changed! }

3. por objeto.

class abc { display() { cout<<"Class abc"; } } // pass object by value void show(abc S) { cout<<S.display(); } // pass object by reference void show(abc& S) { cout<<S.display(); }