El paso de parámetros en C++ se puede hacer de dos formas:
1. Paso de parámetros por valor.
2. Paso de parámetros por referencia.
1. Paso de parámetros por valor.
Pasar parámetros por valor significa que a la función se le pasa una copia del valor que contiene el parámetro actual.
Los valores de los parámetros de la llamada se copian en los parámetros de la cabecera de la función. La función trabaja con una copia de los valores por lo que cualquier modificación en estos valores no afecta al valor de las variables utilizadas en la llamada.
Aunque los parámetros actuales (los que aparecen en la llamada a la función) y los parámetros formales (los que aparecen en la cabecera de la función) tengan el mismo nombre son variables distintas que ocupan posiciones distintas de memoria.
Por defecto, todos los argumentos salvo los arrays se pasan por valor.
Ejemplo de paso de parámetros por valor
El siguiente programa lee un número entero y llama a una función que invierte las cifras del número:
#include <iostream>
using namespace std;
int invertir (int);
int main()
{   int num;
    int resultado;
    cout << "Introduce un numero entero: ";
    cin >> num;
    resultado = invertir(num);
    cout << "Numero introducido: " << num << endl;
    cout << "Numero con las cifras invertidas: " << resultado << endl;
    system("pause");
}
int invertir(int num)
{
    int inverso = 0, cifra;
    while (num != 0)
    {
        cifra = num % 10;
        inverso = inverso * 10 + cifra;
        num = num / 10;
    }
    return inverso;
}
La salida de este programa es:
En la llamada a la función el valor de la variable num se copia en la variable num de la cabecera de la función. Aunque tengan el mismo nombre, se trata de dos variables distintas.
Dentro de la función se modifica el valor de num, pero esto no afecta al valor de num en main. Por eso, al mostrar en main el valor de num después de la llamada aparece el valor original que se ha leído por teclado.


2. Paso de parámetros por referencia.
El paso de parámetros por referencia permite que la función pueda modificar el valor del parámetro recibido.
Vamos a explicar dos formas de pasar los parámetros por referencia:
2.1 Paso de parámetros por referencia basado en punteros al estilo C.
2.2 Paso de parámetros por referencia usando referencias al estilo C++.
2.1 Paso de parámetros por referencia utilizando punteros.
Cuando se pasan parámetros por referencia, se le envía a la función la dirección de memoria del parámetro actual y no su valorLa función realmente está trabajando con el dato original y cualquier modificación del valor que se realice dentro de la función se estará realizando con el parámetro actual.
Para recibir la dirección del parámetro actual, el parámetro formal debe ser un puntero.
Ejemplos de paso de parámetros por referencia
Ejemplo 1:
Programa c++ que lee dos números por teclado y los envía a una función para que intercambie sus valores.
#include <iostream>
using namespace std;
void intercambio(int *, int *);
int main( )
{
    int a, b;
    cout << "Introduce primer numero: ";
    cin >> a;
    cout << "Introduce segundo numero: ";
    cin >> b;
    cout << endl;
    cout << "valor de a: " << a << " valor de b: " << b << endl;
    intercambio(&a, &b); 
    cout << endl << "Despues del intercambio: " << endl << endl;
    cout << "valor de a: " << a << " valor de b: " << b << endl;
    system("pause");
}
void intercambio(int *x, int *y)
{
    int z;                      
    z = *x;
    *x = *y;
    *y = z;
}
La salida de este programa es:
En la llamada, a la función se le envía la dirección de los parámetros. El operador que obtiene la dirección de una variable es &.
intercambio(&a, &b); 
En la cabecera de la función, los parámetros formales que reciben las direcciones deben ser punteros. Esto se indica mediante el operador *
void intercambio(int *x, int *y)
Los punteros x e y reciben las direcciones de memoria de las variables a y b. Al modificar el contenido de las direcciones x e y, indirectamente estamos modificando los valores a y b. Por tanto, pasar parámetros por referencia a una función es hacer que la función acceda indirectamente a las variables pasadas.
Ejemplo 2:
En el siguiente ejemplo, se lee una hora (hora, minutos y segundos) y se calcula la hora un segundo después. El programa utiliza una función segundo_despues que recibe la hora, minutos y segundos leídos y los modifica de forma que al finalizar contienen la hora un segundo después.
// Hora un segundo después
#include <iostream>
#include <iomanip>
using namespace std;
void segundo_despues(int *, int *, int *);
int main()
{   int horas, minutos, segundos;
    do
    {
        cout << "Introduce hora: ";
        cin >> horas;
    }while(horas<0 || horas > 23);
    do
    {
        cout << "Introduce minutos: ";
        cin >> minutos;
    }while(minutos<0 || minutos > 59);
    do
    {
        cout << "Introduce segundos: ";
        cin >> segundos;
    }while(segundos<0 || segundos > 59);

    //llamada a la función
    segundo_despues(&horas, &minutos, &segundos);

    cout << setfill('0');
    cout << endl << "Hora un segundo despues: ";
    cout << setw(2) << horas << ":";
    cout << setw(2) << minutos << ":";
    cout << setw(2) << segundos << endl;
    system("pause");
}

//function c++ que recibe una hora expresada en
//horas, minutos y segundos y calcula la hora
//un segundo después
void segundo_despues(int *h, int *m, int *s)
{
     (*s)++;
     if(*s == 60)
     {
            *s = 0;
            (*m)++;
            if(*m == 60)
                {
                    *m = 0;
                    (*h)++;
                    if(*h == 24)
                        {
                            *h = 0;
                        }
                }
    }
}
Esta función no devuelve nada (aparece void como tipo devuelto), por lo que no es necesario poner la instrucción return.
Mediante return una función solo puede devolver un valor. En casos como la función anterior en los que es necesario devolver más de un valor, habrá que hacerlo pasando los parámetros por referencia.
Este paso de parámetros por referencia basado en punteros es el utilizado por C y por tanto también puede usarse en C++. Pero C++ incorpora una nueva forma de paso de parámetros que no hace uso de punteros.
Es el paso de parámetros utilizando referencias.
2.2 Paso de parámetros utilizando referencias.
Una referencia es un nombre alternativo (un alias, un sinónimo) para un objeto. Una referencia no es una copia de la variable referenciada, sino quees la misma variable con un nombre diferente.
Utilizando referencias, las funciones trabajan con la misma variable utilizada en la llamada. Si se modifican los valores en la función, realmente se están modificando los valores de la variable original.
Ejemplo:
El primer ejemplo del punto anterior utilizando referencias lo podemos escribir así:
#include <iostream>
using namespace std;
void intercambio(int &, int &);
int main( )
{   int a, b;
    cout << "Introduce primer numero: ";
    cin >> a;
    cout << "Introduce segundo numero: ";
    cin >> b;
    cout << endl;
    cout << "valor de a: " << a << " valor de b: " << b << endl;
    intercambio(a, b); 
    cout << endl << "Despues del intercambio: " << endl << endl;
    cout << "valor de a: " << a << " valor de b: " << b << endl;
    system("pause");
}
void intercambio(int &x, int &y)
{
    int z;                      
    z = x;
    x = y;
    y = z;
}
En la declaración de la función y en la definición se coloca el operador referencia a & en aquellos parámetros formales que son referencias de los parámetros actuales:
void intercambio(int &, int &);  //declaración de la función
void intercambio(int &x, int &y)  //definición de la función
Cuando se llama a la función:   
intercambio(a, b); 
se crean dos referencias (x e y) a las variables a y b de la llamada. Lo que se haga dentro de la función con x e y se está haciendo realmente con a y b.
La llamada a una función usando referencias es idéntica a la llamada por valor.
Ejemplo:
El segundo ejemplo anterior, utilizando referencias:
// Hora un segundo después
#include <iostream>
#include <iomanip>
using namespace std;
void segundo_despues(int &, int &, int &);
int main()
{   int horas, minutos, segundos;
    do
    {
        cout << "Introduce hora: ";
        cin >> horas;
    }while(horas<0 || horas > 23);
    do
    {
        cout << "Introduce minutos: ";
        cin >> minutos;
    }while(minutos<0 || minutos > 59);
    do
    {
        cout << "Introduce segundos: ";
        cin >> segundos;
    }while(segundos<0 || segundos > 59);
    segundo_despues(horas, minutos, segundos);
    cout << setfill('0');
    cout << endl << "Hora un segundo despues: ";
    cout << setw(2) << horas << ":";
    cout << setw(2) << minutos << ":";
    cout << setw(2) << segundos << endl;
    system("pause");
}

void segundo_despues(int &h, int &m, int &s)
{
     s++;
     if(s == 60)
     {
            s = 0;
            m++;
            if(m == 60)
                {
                    m = 0;
                    h++;
                    if(h == 24)
                        {
                            h = 0;
                        }
                }
    }
}