C++에서 함수에 인수를 전달하는 방법은 크게 세가지가 있습니다.
① 값을 전달하는 방식 - Pass by Value
② 포인터를 사용한 참조 전달 방식 - Pass by Reference using Pointer
③ 레퍼런스 전달 방식 - Pass by Reference
값을 전달하는 방식은 함수를 호출할 때 전달한 인수를 매개변수에 복사하여 사용하기 때문에 원본 데이터에 영향을 미치지 못합니다. 함수의 실행이 끝날 때 오직 하나의 값이 리턴되기 때문에 여러개의 반환값을 받을 수가 없죠. 예를 들어 두 변수의 값을 바꾸는 경우는 하나의 반환값으로 해결이 안됩니다.
이런 경우 포인터를 사용해서 참조를 전달하면 이 문제가 해결됩니다.
포인터 뿐 아니라 레퍼런스를 사용해도 됩니다.
swap 함수를 사용해서 알아보겠습니다.
함수를 호출하면 매개변수는 지역변수로 선언됩니다. 함수 호출이 종료할 때 소멸되죠. 즉 지역변수에서 매개변수를 조작해도 다시 바깥으로(main 으로) 나오면 그 내용은 사라집니다. 물론 처음부터 main 에서 전달한 인수에는 아무런 영향도 없습니다.
* 지역 mySwap의 변수들만 swap된 것을 볼 수 있고 main의 변수들은 영향이 없습니다.
포인터를 사용하는 방식은 값 전달의 코드에 약간의 수정을 하면 됩니다.
우선 함수의 매개변수를 포인터로 선언합니다. 이렇게 되면 함수가 호출될 때 지역변수에는 정수형 포인터 두개가 만들어 집니다. 그리고 함수를 호출하면서 변수의 주소를 인수로 전달합니다. 여기서 & 는 주소연산자입니다. x와 y의 32비트(혹은 64비트) 주소값이 전달되겠죠.
여기서 다시 한번 구분해보면 인수는(argument) main함수에서 전달하는 값이고 매개변수(parameter)는 호출된 함수가 인수를 전달받아서 지역에 복사하여 생성하는 값입니다. 1번에서는 main에서 정수인 x, y 를 mySwap의 x, y에 그대로 복사했습니다. 그런데 여기서는 x, y의 주소를 받아서 포인터인 *ptrx, *ptry 에 저장하고 있습니다. 주는 쪽의 형식과 받는 쪽의 형식은 다르지만 호환이 되기 때문에 정상적으로 작동합니다.
실행하면 스왑 후 main 의 변수가 바뀌어있는 것을 볼 수 있습니다.
세번째 레퍼런스 전달 방식입니다.
함수의 매개변수를 보면 레퍼런스 연산자 & 가 선언되어 있습니다. 레퍼런스 연산자는 주소연산자 &와 다르기 때문에 혼동에 주의합니다.
일단 매개변수를 레퍼런스로 받은 후에는 main 함수의 변수를 사용하는 것 처럼 값에 접근할 수 있습니다. 호출할 때의 형태를 보면 값 전달 방식(pass by value)와 동일합니다. 인수는 그냥 변수를 전달하고 있습니다. 이것을 함수에서 레퍼런스 변수로 받아가지고 갑니다.
아래와 같은 변수가 지역에 선언되는 것 이죠.
int &refx = x;
int &refy = y;
이들은 레퍼런스 변수의 특징을 그대로 가지고 있으니 원본의 값을 바꿀 수는 있어도 레퍼런스 변수 자체가 다른 정수형 변수를 가리킬 수가 없습니다. 안정성이 좋아지죠.
레퍼런스 전달로 main의 변수가 변경 된 것을 볼 수 있습니다.
함수에 값을 전달하는 방식을 비교해보고 레퍼런스 전달 방식까지 알아봤습니다.
포인터로 작성된 것들은 레퍼런스 방식으로 재작성될 수 있는데 이렇게 하면 간접참조연산자 (* 역참조 연산자)를 사용하지 않아도 되니 코드가 읽기 쉽다는 장점이 있습니다.
포인터가 사용되는 곳에는 레퍼런스가 따라다닐 것 입니다. 레퍼런스에 대하여 정리를 잘 해 두면 도움이 됩니다.
* 레퍼런스 전달 방식 예제코드
#include <iostream>
void mySwap(int &x, int &y);
int main()
{
int x = 9;
int y = 77;
Line;
cout << " main | [스왑 전] x: " << x
<< " y: " << y << endl;
mySwap(x, y);
Line;
cout << " main | [스왑 후] x: " << x
<< " y: " << y << endl;
return 0;
}
void mySwap(int &refx, int &refy)
{
int temp;
temp = refx;
refx = refy;
refy = temp;
Line;
cout << " mySwap | [스왑 후] *refx: " << refx
<< " *refy: " << refy << endl;
}