"Call by value"와 "call by reference"는 함수 호출 방식을 나타내는 용어
이 두 가지 방식의 주요 차이점: 함수에 인수를 전달하는 방법 & 함수가 인수를 처리하는 방법
1. Call by Value (값에 의한 호출):
- 함수에 매개 변수로 ‘값’을 전달합니다.
- 함수 내에서 매개 변수는 별도의 변수로 취급되며, 인수의 값이 복사되어 매개 변수에 저장됨
- 따라서 함수 내에서 매개 변수의 값을 변경하더라도 호출자(caller/원본)의 변수는 영향을 받지 않음
- C++에서 함수의 기본 호출 방식은 "call by value"
void modifyValue(int x) {
x = x + 10;
}
int main() {
int num = 5;
modifyValue(num);
std::cout << "num: " << num << std::endl; // 출력 결과: num: 5
return 0;
}
2. Call by Reference (참조에 의한 호출):
"주소/참조 값을 전달받아서, 함수 외부에 선언된 변수에 직접 접근하는 형태의 함수 호출"
- 함수 입력으로 주소/참조 값이 전달되었다는 사실이 중요한 게 아니라
- 입력된 주소/참조 값을 통해 직접 외부 변수를 참조하여 모종의 행위(읽기/조작 등)을 했을 때 call-by-reference라 칭할 수 있음
- 함수에 매개 변수로 ‘변수의 참조/주소’를 전달
- 함수 내에서 매개 변수는 원래 변수와 동일한 메모리 위치를 참조하므로,
함수에서 매개 변수를 수정하면 호출자(원본)의 변수가 직접 영향을 받음 - C++에서는 매개 변수를 참조로 전달하려면 참조자(reference) 또는 포인터(pointer)를 사용해야 함
(1) 포인터 *를 활용 (주소)
void modifyValueByPointer(int* x) {
*x = *x + 10;
}
int main() {
int num = 5;
modifyValueByPointer(&num);
std::cout << "num: " << num << std::endl; // 출력 결과: num: 15
return 0;
}
- 늘 느끼는 건데.. (?) 주소값은 메모리가 할당된 위치이고, 이 주소값 자체는 변하지 않고 고정됨.
반면, 해당 주소에 저장된 value 자체는 변형&조작의 대상이 됨.
- 단, 이하와 같은 방식으로, 포인터를 통해 value를 직접 조작하는 것을 막을 수 있다.
const int* ptr1 = # //ptr1를 이용해서 num의 value를 바꿀 수 없음 //*ptr1를 상수화시켰다는 의미
*주의할 점은, ptr = 2;는 ptr이 const 변수이기 때문에 컴파일 에러가 발생 하지만
num = 2;는 num이 non-const 변수이기 때문에 정상이다. 즉, 포인터 변수가 가리키는 num 자체가 상수화가 되는 것이 아니다.
- (완전 별개의 이야기지만) 포인터 주소값 자체를 상수화시킬 수도 있다.
int* const ptr2 = # // num의 주소값인 ptr2 자체가 상수화됨
(2) 참조 &를 활용 (별명)
void modifyValueByReference(int& x) {
x = x + 10;
}
int main() {
int num = 5;
modifyValueByReference(num);
std::cout << "num: " << num << std::endl; // 출력 결과: num: 15
return 0;
}
- int& x에서 &는 C++에서 "참조자"를 나타내는 연산자
- 자료형 바로 뒤에 &가 붙음!!! (변수명 앞에 &가 붙는 게 아니라 ~~~.)
- 참조자는 변수에 대한 별명(alias)이며, 원본 변수를 직접 참조하게 함.
이것은 값(value) 자체가 아니라 변수에 대한 참조(reference)를 함수에 전달함을 의미함
- int& x에서 x는 참조자의 이름이고, int는 참조할 변수의 데이터 타입을 나타냄 (int& x: "정수형 변수에 대한 참조를 받는다")
참조자를 사용할 때의 특징
- 원본 변수의 별명: 참조자는 원본 변수의 별명으로 동작함, 따라서 참조자를 통해 값을 읽거나 수정하면 원본 변수에도 동일한 작업이 반영됨.
- 포인터와 다른 점: 참조자 != 포인터.
포인터는 메모리 주소를 저장하고 간접 참조를 통해 값을 읽고 쓰고 조작할 수 있지만,
참조자는 변수에 직접적으로 연결되어 있으므로 포인터보다 사용하기 간편함 - 값 전달이 아닌 참조 전달: 함수에 참조자를 매개 변수로 전달하면 함수 내에서 원본 변수를 직접 조작할 수 있으며, 호출자의 변수도 변경됨(이 성질은 포인터에서도 동일~)
'개발 > c++' 카테고리의 다른 글
[c++] 클래스 디자인하기 (feat. 멤버변수 / 멤버함수 / private & public / inline) (0) | 2023.09.04 |
---|---|
[c++] 인라인 함수의 효용 (3) | 2023.09.04 |
[c++] 메모리의 세 가지 영역 : 데이터, 스택, 힙 (0) | 2023.09.03 |
[c++ 프로그래밍 입문] 5-2. 함수와 배열&구조체&포인터 (0) | 2023.08.30 |
[c++ 프로그래밍 입문] 5-1. 함수의 기초 (0) | 2023.08.30 |