함수의 인자 전달 방식
'값에 의한 호출(call by value) ' 과 ' 주소에 의한 호출(call by address) ' 으로 함수의 인자를 전달하는 방식이 있습니다.
간단히 이해하려면 값에 의한 호출은 "내가 가진 값을 함수에 전달하기만 하는 것"이고 주소에 의한 호출은 "내가 가진 값의 주소를 함수에 전달하여 변수 값을 바꾸고자 하는 것"이라고 생각하면 됩니다.
예시를 들어 설명하자면 아래코드의 swap 함수의 역할을 주의 깊게 봅시다.
#include <iostream> #include <iostream>
using namespace std; using namespace std;
void swap(int a, int b){ void swap(int *a, int *b){
int temp; int temp;
temp = a; temp = a;
a = b; a = b;
b = temp; b = temp;
} }
int main(){ int main(){
int x=1,y=2; int x=1,y=2;
swap(x,y); swap(&x,&y);
return 0; return 0;
} }
// 값에 의한 호출 // 주소에 의한 호출
- 값에 의한 호출
매개 변수 x, y가 swap함수에 전달되어 a, b의 값을 교환해 a=2, b=1이 되며, 함수 종료 시 a, b는 사라지고 x, y의 값은 그대로입니다.
정리하면, ' 값에 의한 호출 '은 함수의 매개 변수에 실인자 값(이 경우 변수의 주소에 저장된 값)을 복사하여 전달하는 방식입니다.
- 주소에 의한 호출
매개 변수 x, y의 주소가 swap함수에 전달되어 주소에 있는 값들이 a, b의 교환하는 값으로 동작해, 함수 종료 시에도 x, y가 가리키는 주소 안의 값들이 교환되었으므로 x=2, y=1이 됩니다.
정리하면, ' 주소에 의한 호출 '은 주소를 직접 포인터 타입의 매개변수에 전달하는 방식입니다. 배열과 포인터가 유사하다는 것을 알 텐데 포인터가 변수의 주소를 가리킨다면, 배열의 이름이 배열의 주소를 가리킨다고 볼 수 있습니다.
함수 호출 시 객체 전달
C언어에서는 인자 전달 방식의 이해에 큰 어려움이 없지만 C++은 객체 자체를 함수로 전달하는 경우가 있기 때문에 활용도는 높지만 실수할 가능성이 높습니다.
- 값에 의한 호출로 객체 전달
매개 변수가 객체가 된 것으로 이해하면 됩니다. 코드는 아래와 같이 작성할 수 있습니다.
void plus_box(Rectangle a){
int area = a.getArea();
a.getArea(area*area);
}
int main(){
Rectangle box(10); // box라는 객체 생성
plus_box(box); // plus_box라는 함수에 객체 전달
}
plus_box에 객체 box(10)가 전달되어 객체 a의 area값을 변화시킵니다. (클래스의 멤버를 선언할 때 매개변수로 area를 받게 했다면 a의 area은 100이 되겠지요.)
다음 동작에서 아무 문제가 없어 보이지만 매개변수 객체의 생성자는 실행되지 않고 소멸자만 실행되는 비대칭구조이기에 문제가 일어납니다.
매개 변수의 생성자가 실행되지 않고 컴파일이 되는 이유는?
생성자가 실행된다면 생성자가 선언한 형태로 초기화 돼버립니다. 때문에 전달받은 객체의 값이 매개 변수 객체의 생성자의 호출로 인해 초기화되는 경우를 방지하기 위해서 생성자가 실행되지 않습니다.
하지만 비대칭구조 때문에 문제가 발생할 수 있는데 이때 "복사 생성자"를 대신 호출합니다. 자세한 내용은 다음에 다룹니다.
- 주소에 의한 호출
객체의 주소만 전달하므로 매개변수 객체의 생성자 문제는 알아서 해결됩니다.
void plus_box(Rectangle *a){
int area = a->getArea();
a->getArea(area*area);
}
int main(){
Rectangle box(10); // box라는 객체 생성
plus_box(&box); // plus_box라는 함수에 객체 전달
}
당연하게도 객체 box의 area값이 100이 됨을 알 수 있습니다.
객체 치환 및 객체 리턴
- 객체 치환
객체 치환이란 객체의 모든 데이터가 비트 단위로 복사됨을 의미합니다. 객체의 내용물이 복사될 뿐 같은 객체가 되지는 않으며 당연하지만 동일한 클래스 타입에 대해서만 적용됩니다.
Rectangle a_1();
Rectangle a_2(10);
a_1 = a_2; // a_1객체가 a_2객체로 바뀌것이 아니고, 내용물이 같아지는 것을 의미합니다.
- 객체 리턴
객체 리턴은 말 그대로 함수가 객체를 리턴하는 경우이며, 이때 객체는 '복사본'이 만들어지고 함수의 목적에 따라 호출된 곳으로 전달된 후 소멸합니다.
Rectangle getArea(){
Rectangle temp(10);
return temp;
}
int main(){
...
Rectangle a;
a = getArea(); //temp 객체가 a에 복사되며 a의 내용물이 temp(10)과 동일해집니다.
return 0;
}
'프로그래밍 > C++' 카테고리의 다른 글
[C++] 5장. #2 참조와 복사 생성자 (1) | 2023.12.08 |
---|---|
[C++] 4장. #2 this 포인터와 string 클래스 (0) | 2023.12.08 |
[C++] 4장. #1 객체 포인터와 객체 배열 (0) | 2023.12.04 |
[C++] 3장. #2 접근 지정자와 인라인 함수 (1) | 2023.12.03 |
[C++] 3장. #1 클래스와 객체 (0) | 2023.12.02 |