LANG/C++

[C++]02-4.참조자(Reference)와 함수

혀니리리 2023. 5. 11. 22:51
728x90

참조자의 활용에는 함수가 큰 위치를 차지함.

1.Call-by-value & Call-by-reference

//Call-by-value
void SwapByValue(int num1, int num2)
{
	int temp = num1;
    num1 = num2;
    num2 = temp;
}

int main(void)
{
	int val1 = 10;
    int val2 = 20;
    SwapByValue(val1, val2);		  //val1과 val2에 저장된 값이 바뀌기를 기대함
    cout << "val1: " << val1 << endl; //10 출력
    cout << "val2: " << val2 << endl; //20 출력
    return 0;
}

예상된 결과가 나오지 않는 이유: 어찌보면 당연...

함수 내에서만 효력이 존재하기 때문에 나오면 그 값이 반영되지 않고 기존의 10, 20을 출력함.

 

//Call-by-reference
void SwapByRef(int * ptr1, int * ptr2)
{
	int temp = *ptr1;
    *ptr1 = *ptr2;
    *ptr2 = temp;
}

int main(void)
{
	int val1 = 10;
    int val2 = 20;
    SwapByValue(&val1, &val2);		  //val1과 val2에 저장된 값이 바뀌기를 기대함
    cout << "val1: " << val1 << endl; //20 출력
    cout << "val2: " << val2 << endl; //10 출력
    return 0;
}

포인터를 들고 가기 때문에 예상된 값이 나옴.

 

2.Call-by-address? Call-by-reference!

call-by-address라고 부르지 않는이유: 주소 값이 전달되었다는 사실이 중요한 게 아니라, 주소값이 참조의 도구로 사용되었다는 사실이 중요!

int * SimpleFunc(int * ptr)
{
	return ptr + 1; //주소값을 증가시켜서 반환
}
//call-by-reference아님

int * SimpleFunc(int *ptr)
{
	if(ptr == NULL)
    	return NULL;
    *ptr = 20;
    return ptr;
}
//함수 외부에 선언된 변수를 '참조'함
//Call-by-reference

 

C++에서는 함수 외부에 선언된 변수의 접근 방법으로 두 가지가 존재함.

1.주소 값을 이용한 Call-by-reference

2.참조자를 이용한 Call-by-reference

 

3.참조자를 이용한 Call-by-reference

참조자가 좋은 이유... 랄까

매개변수는 함수가 호출되어야 초기화가 진행되는 변수들이므로 매개변수에 있다고 초기화가 이루어지지 않은 것이 아니라, 함수 호출 시 전달되는 인자로 초기화를 하겠다는 의미임.

 

윤성우 C++ p.80 3번 정답

ptr1, ptr2를 매개변수로 넣으라고 했으므로..

#include <iostream>
using namespace std;

void SwapPointer(int *(&pref1), int *(&pref2))
{
	int *ptr = pref1;
    pref1 = pref2;
    pref2 = ptr;
}

int main(void)
{
	...
    SwapPointer(ptr1, ptr2);
    ...
}

참조자의 이점: 포인터보다 잘못 사용할 확률 적고 활용이 쉬움

 

4.참조자를 이용한 Call-by-reference의 황당함과 const참조자

참조자의 단점

call-by-value가 아닌게 단점이 됨

 

원래같으면

int num = 24;

HappyFunc(num);

cout << num << endl;

 

-> call-by-value로 인해 24가 출력되어야 하지만

void HappyFunc(int &ref) { . . . } 이 되면 안에서 값이 바뀔 수 있으므로

함수의 원형, 함수의 몸체 까지 문장 단위로 확인해야 함.

 

 

이러한 문제 때문에

 

void HappyFunc(const int &ref) { . . .}

=> "함수 내에서 참조자를 통한 값의 변경을 진행하지 않을 경우, 참조자를 const로 선언해서 함수의 원형만 봐도 값의 변형이 이뤄지지 않음을 알 수 있게 한다."

 

5.반환형이 참조형(Reference Type)인 경우

1) 반환형 참조형, int &num2 = 참조형반환(int &) 형태로 받는 경우

결과: 말그대로 num1의 참조형이 num2라는 뜻이므로 num1과 num2는 같은 변수인 듯이 작동

 

2)int num2 = 참조형반환(int &) 형태로 받는 경우

 

int 형으로 만들어진 새로운 변수가 num1를 참조하는 것이므로 num2는 num1과 다른 변수가 됨

 

3)참조자를 반환하되, 반환형은 기본자료형인 경우

결과는 2와 동일

but 

int num2 = RefRetFuncTwo(num1);   (0)

int &num2 = RefRetFuncTwo(num1); (x) => 상수를 받는 것과 같으므로

 

6.잘못된 참조의 반환

int& RetuRefRunc(int n)
{
	int num = 20;
    num += n;
    return num;
}

int &ref = RetuRefFunc(10);

=> 지역변수 num에 저장된 값을 반환하지 않고, num을 참조의 형태로 반환하고 있음

따라서 num에 ref라는 또 하나의 이름이 붙게 되며,

함수가 반환이 되면 정작 지역변수 num은 소멸됨... 

 

주의가 필요!

 

7.const 참조자의 또 다른 특징

문제점

const int num = 20;
int &ref = num;
ref += 10;
cout << num << endl;

const를 통해 이미 상수화했는데 고치면 컴파일 에러를 일으킨다. 

따라서

const int num = 20;

const int &ref = num;

이런 식으로 선언해야 함.

 

또한, const int &ref = 50;같이 상수 참조가 가능함.

-> 장난해? A.워워, 8을 봐.

 

8.어떻게 참조자가 상수를 참조하냐고요!

'임시변수'라는 개념 도입.

굳이 어렵게 이런 개념 왜 만들었냐??

 

이런 케이스 때문

int Adder(const int &num1, const int &num2)
{
	return num1 + num2;
}

cout << Adder(3, 4) << endl;

이런 코드 작성할 때 3,4집어넣기 위해 일일히 int n1 = 3; int n2 = 4; Adder(n1,n2) 하면 귀찮으니까...

728x90