Ao passar parâmetros para uma função, você deve considerar se isso é feito como um parâmetro de valor (chamada por valor) ou como um parâmetro de referência (chamada por referência). Da mesma forma, ao escrever uma função, você deve considerar qual tipo de passagem de parâmetro é melhor para seu propósito. Este artigo explica a diferença entre chamada por valor e chamada por referência e fornece dicas práticas para usá-las.
Resumo
- Chamada por valor (parâmetro de valor): Em muitas linguagens de programação, os parâmetros são passados como uma cópia;
- Chamada por referência (parâmetros de referência): Alterações nos parâmetros afetam os valores originais, por ex. B. para funções com vários valores de retorno.
- Cópia de uma referência: Para parâmetros de objetos, muitas linguagens passam apenas referências ou ponteiros, não o objeto inteiro.
- Uso de const: Em C++, objetos que não devem ser alterados podem ser marcados como const para evitar erros.
- Java: Somente chamada por valor, os valores são copiados para tipos de valor, as referências são copiadas para tipos de referência.
- C#: Chamada por valor por padrão, mas capacidade de impor chamada por referência usando palavras-chave “ref” e “out”.
- Observe as diferenças: A diferença entre chamada por valor e chamada por referência influencia o andamento do programa e deve ser levada em consideração na programação.
Chamada por valor – parâmetro de valor
Em muitas linguagens de programação, os parâmetros normalmente são passados para funções por meio de uma cópia. Isso é chamado de chamada por valor. Isso significa que a cópia é usada dentro da função chamada e as alterações não afetam o valor original.
Definição de uma função com parâmetros de valor em C++
// Addiere a und b.
int CHelper::Sum(int a, int b)
{
// Sowohl 'a' als auch 'b' werden "by value" übergeben
return a + b;
}
Call-by-Reference – parâmetros de referência
Quando passado como referência, as alterações nos parâmetros afetam os valores originais. Na prática, isso é usado, por exemplo, quando uma função teria vários valores de retorno. Abaixo está um exemplo de função que usa chamada por referência:
Definição de uma função com parâmetros de referência em C++
void CHelper::Swap(int& a, int& b)
{
// Sowohl 'a' als auch 'b' werden "by reference" übergeben,
// deshalb ist eine Zuweisung möglich.
int temp = a;
a = b;
b = temp;
}
A função Swap troca o conteúdo das variáveis. Para que isso aconteça, os valores devem ser passados por referência, caso contrário a função não teria influência nas variáveis originais.
Cópia de uma referência
Se os parâmetros de função são objetos, é prática comum em muitas linguagens de programação que apenas referências ou ponteiros sejam passados para esses objetos, ou seja, apenas o endereço no qual o respectivo objeto é armazenado. Se chamada por valor for usada nesse caso, não é o objeto que é copiado, mas sim o elemento que contém o endereço de memória do objeto. As referências não podem ser copiadas em C++, mas os ponteiros são copiados por padrão, como mostra o exemplo a seguir:
Passando um ponteiro por valor
void PrintAndDeleteMyObject(CExampleClassBase* object)
{
// Print vom übergebenen Objekt wird ausgeführt
object->Print ;
//Exclui o objeto
excluir objeto;
// O ponteiro só é redefinido localmente aqui,
// nada muda para o chamador da função.
// Ou seja, ainda está no ponteiro original
// sempre contém o endereço do objeto excluído,
// o que pode levar a erros.
objeto = NULO;
}
Se você quiser passar o ponteiro original da função para que ela possa ser manipulada, você também pode passar o ponteiro como referência usando o operador &:
void PrintAndDeleteMyObject(CExampleClassBase*& object)
{
// Print vom übergebenen Objekt wird ausgeführt
object->Print ;
//Exclui o objeto
excluir objeto;
// O ponteiro do chamador agora está definido como NULL
// reiniciar. Isso só funciona porque
//o ponteiro foi passado por referência.
objeto = NULO;
}
Passar um ponteiro por referência quase nunca é necessário na prática. Antes de usar tais construções, você deve pensar cuidadosamente se não existe uma maneira melhor e mais simples.
Chamada por valor e chamada por referência em C++
Em C++, como em muitas outras linguagens de programação, a chamada por valor é a norma. Portanto, tanto os ponteiros quanto os valores normais são copiados quando passados para funções. Usando o caractere & você pode forçar a chamada por referência e assim evitar uma cópia. Os objetos são frequentemente passados com um ponteiro ou por referência, uma vez que uma cópia do objeto geralmente não é desejada.
Se você passar um objeto que não deve ser alterado por referência, poderá usar a palavra-chave const para marcá-lo como constante e, portanto, “somente leitura”. Usar const o mais extensivamente possível é chamado de correção const, uma técnica de programação avançada em C++ que pode ser usada para evitar erros.
Também pode acontecer que seja necessário que o endereço de um ponteiro seja manipulado por uma função. Neste caso você pode passar o ponteiro por referência (ver exemplo acima).
Chamada por valor e chamada por referência em Java
Em Java existe apenas chamada por valor. Isso significa que para tipos de valor (tipos de dados primitivos como inteiros) os valores são copiados e para tipos de referência (objetos) as referências a objetos são copiadas. Lentamente novamente: se você passar um número inteiro, flutuante ou similar, o valor será copiado e nada poderá ser alterado nos valores originais do chamador. Ao passar um objeto, a referência é copiada. No entanto, isso significa que o mesmo objeto ainda é referenciado, portanto, alterações nele certamente afetarão o objeto original.
Parâmetros de valor e parâmetros de referência em Java
public void printData(int wertParameter, Object referenzParameter)
{
System.out.print(wertParameter);
System.out.print(referenzParameter);
return;
}
Ambos os parâmetros de printData são copiados. Atribuições a parâmetros de valor só teriam efeito dentro da função. Alterações no objeto para o qual o parâmetro de referência aponta também teriam um efeito externo, pois seria alterado o objeto e não a referência copiada.
Chamada por valor e chamada por referência em C#
Java e C# são muito semelhantes como linguagens de programação. Eles também não diferem muito quando se trata de passagem de parâmetros. Por padrão, C# também passa por valor para tipos de valor, os valores são copiados, e para tipos de referência, as referências são copiadas. No entanto, C# também oferece a opção de forçar chamada por referência. Existem também as palavras-chave ref e out.
chamar por valor em C#
public void swapContent(ref int a, ref int b)
{
int temp = a;
a = b;
b = temp;
}
A palavra-chave ref força a chamada por referência ao passar parâmetros e alterações nos parâmetros também afetam os valores originais.
Conclusão
A diferença entre chamada por valor e chamada por referência pode influenciar significativamente o andamento do programa. Para que você possa escrever bons programas, você deve sempre ter clareza sobre o que exatamente acontece com seus parâmetros quando uma função é chamada. É melhor abrir imediatamente o ambiente de desenvolvimento de sua escolha e experimentar as diversas opções do depurador.
FAQ: Perguntas frequentes sobre chamada por valor e chamada por referência
A chamada por valor passa uma cópia da variável enquanto a chamada por referência passa a variável.
Com a chamada por valor, os argumentos reais e formais são criados em locais diferentes, enquanto com a chamada por referência, os argumentos reais e formais são criados no mesmo local.
Chamada por valor é um método que passa argumentos para funções. O valor real é copiado no parâmetro formal. Por padrão, a programação C usa chamada por valor para passar argumentos. Isso significa que o código dentro de uma função não pode alterar os argumentos passados.
A maneira Java de chamar um método por um valor é chamada chamada por valor. Nesse caso, cópias dos valores são passadas para os parâmetros em vez dos valores reais. Uma variável é uma referência a um endereço de memória. Isto é de conhecimento comum.