안녕하세요 삽잡이 입니다...
월요병이 발병하여... 멍한 하루를...
TV에서 봤는데 월요병에 걸리지 않기 위해서는 평상시와 비슷한 패턴의 주말을 보내야한다고 하더군요...
그게 되나요...
하지만 유용한 정보는 하나 알게 되었죠...
예를들어 5시간 정도 자던 사람에게 있어서 주말에 +2 시간정도 추가적인 수면을 취한다면
피로가 보다 더 풀리게 된다고 합니다...
하지만 그 이상으로 잔다면 생체 시계가 엉망이 되어 환상적인 월요병이 우리에게 찾아온다고 하군요...
아무튼... 월요일이라... 월요월요하군... 헙... ㅋㅋㅋ
자... 오늘은 뜬금없이 기초로 돌아가보려고 합니다...
바로 '&' 참조형 연산자에 대해 썰을 풀어보려고요...
월요월요하니 뜬금없는 복습으로 머리 정리를 해보도록 하겠습니다...
& 연산자는 변수 앞에 써서 주소를 나타내지 않나요...
맞습니다... 하지만 C++에서는 추가적인 기능을 제공합니다...
바로 레퍼런스 변수!
이는 무엇인가 하나면 기존의 변수에 별명을 하나 붙여주는 것입니다.
포인터와 다르게 한 변수에 주소값을 담는 기능을 가지는 변수가 아니라
한 변수와 한몸을 이룬다는 것이죠.... 부끄러워라... 죄송합니다.. 월요월요해서...
레퍼런스 변수의 중요한 점은 바로, 선언과 동시에 초기화를 해야한다는 것입니다.
int &zap = sap;
이렇게요... 그리고 반드시 변수를 받아야합니다....
레퍼런스 변수는 어떠한 변수와 한몸을 이루게 되는 것이니까요...
아무튼...
우리는 오늘 레퍼런스 변수에 대한 기초적인 내용을 알고 있다는 가정하에
이 레퍼런스 변수를 함수의 매개변수로 받을 때와 반환형으로 보낼 때에 대해서
생각을 해보는 시간을 가져보려고 합니다...
예를 들어보도록 하죠...
우선 기초적인 call-by-value, call-by-reference의 대한 내용은 생략하겠습니다...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | void Swap(int *psap, int *pzap) { int temp = *psap; *psap = *pzap; *pzap = temp; } void main() { int sap = 10; int zap = 20; Swap(&sap, &zap); cout<<"sap : "<<sap<<endl; cout<<"zap : "<<zap<<endl; } | cs |
이와 같이 sap, zap 이라는 변수들의 주소를 매개변수로 보내고
Swap 함수에서는 이 주소의 값을 참조하기 위해 * (포인터 연산자)를 사용하여
직접 주소로 접근하여 값을 수정하고 있습니다....
하지만 레퍼런스 변수를 사용하면 보다 간략하고 효율적으로
Swap 함수를 구현할 수 있습니다...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | void Swap(int &rsap, int &rzap) { int temp = rsap; rsap = rzap; rzap = temp; } void main() { int sap = 10; int zap = 20; Swap(sap, zap); cout<<"sap : "<<sap<<endl; cout<<"zap : "<<zap<<endl; } | cs |
차이를 확인하실 수 있겠습니까?
바로 매개변수를 &... 즉 레퍼런스 변수로 받고 있습니다....
이렇게 되면 sap이라는 변수에는 rsap이라는 별명이
zap이라는 변수에는 rzap이라는 별명이 붙게 되는 것이죠...
굳이 Swap 함수 내에 지역변수에 대한 메모리 할당을 할 필요없이
레퍼런스 변수를 사용하여 값을 바꿀 수 있게됩니다...
여기서 의문이 생기실 수 있습니다... 레퍼런스 변수는 선언과 동시에 초기화를 해야하는데
이미 Swap 함수에 매개변수로 레퍼런스 변수들을 선언해두고 있지 않느냐...
아닙니다... Swap 함수가 호출이 되면서 값이 전달되게 되는데요
이때 매개변수들이 Stack 메모리에 올라가게 됩니다...
이와 동시에 레퍼런스 변수에 각각 인자로 전달된 변수들이 초기화가 되기 떄문에 전혀 문제가 없죠...
아무튼... 매개 변수에 레퍼런스 변수를 사용하면 이와같은 편의성을 가지게 됩니다...
다음으로 살펴보고자 하는 것이 바로 반환형으로 레퍼런스 형을 사용하는 것입니다...
int 형으로 값을 반환할 때에는 반환형으로 int를 써줘야하고
double형으로 값을 반환하고자 할 때에도 반환형을 double로 써줘야하는등...
이와같이 프로그래밍 언어에서는 서로 약속이라는 것이 있죠...
그렇다면 반환형이 레퍼런스일 경우에 대한 예시를 살펴보도록 하겠습니다...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | int& Ref(int &rsap) { rsap++; return rsap; } void main() { int sap = 10; int &zap1 = Ref(sap); int zap2 = Ref(sap); zap1 += 100; zap2 += 10; sap +=1; cout<<"sap : "<<sap<<endl; cout<<"zap1 : "<<zap1<<endl; cout<<"zap2 : "<<zap2<<endl; } | cs |
zap1은 레퍼런스형 변수이고 zap2는 그냥 평범한 변수입니다.
결과에 대해서 생각을 우선 해보도록 합시다...
전체적인 코드의 과정을 살펴보도록 하죠...
10의 값을 가지고 있는 sap변수가 Ref() 함수에 인자가 됩니다...
즉 sap == rsap 이 되는 것이죠....
Ref 함수내 rsap의 값이 변경된다면 자연스럽게 sap 변수의 값또한 변경이 됩니다...
rsap은 sap변수의 레퍼런스 변수니까요... 한몸이죠...
자... 이제 반환을 int& 즉, 레퍼런스형으로 반환을 합니다...
이 뜻은... rsap == &zap1 이 되는 것이죠...
즉, sap == rsap == zap1 이 모두가 동일하게 됩니다...
따라서 최종적으로 113이라는 값이 저장됩니다..
왜 112가 아닐까요?
아래 설명을 마저 하고 말씀드리도록 하죠...
zap2의 변수같은 경우에는 sap을 인자로 보내고 그에 대한 결과 값을 대입합니다...
이를 표현한다면 sap == rsap 은 지만
rsap과 zap2는 같지 않습니다...
왜냐하면 zap2는 int형 정수를 저장하는 변수이니까요... 레퍼런스형이 아닙니다...
즉 sap의 변경된 값을 zap2라는 변수에 대입하는 것입니다...
한몸이 되는게 아니죠... 하하...
자... 둘의 차이를 아셨나요?
레퍼런스형은 쉽게 생각하면 하나의 변수를 공유한다는 개념으로 이해하시면 편할 것 같습니다...
zap2와 같은 경우에는 그냥 값을 대입한 것입니다.
아무리 레퍼런스형으로 반환을 했어도 저장하는 변수가 일반 변수라면
참조하는 것이 아닌 단순히 값 저장만을 하는 것이죠...
자... 그럼 아까 마저 설명하지 못한 부분을 마무리 짓겠습니다...
바로 zap1의 결과가 왜 112가 아닌 113이 출력되냐입니다...
차근차근 살펴보도록 하겠습니다...
sap의 변수에는 10이 들어있습니다.
sap이 Ref()함수의 인자로 호출되는데 이 Ref()함수의 매개변수를 레퍼런스 형으로 받고 있습니다.
즉, sap과 rsap은 메모리를 공유하는 사이가 되는 것이죠...
그런데 또 반환형이 레퍼런스형입니다...
이에 레퍼런스 변수인 zap1이 rsap의 메모리를 공유하게 되죠...
즉 sap == rsap == zap1 이 성립하게 됩니다.
자... 정리 잘해보세요... 이제 시작합니다 하하...
말로 풀어쓰니 복잡합니다... 잘 이해해보시길... 허허... 이런 무책임한 사람아...
zap1에 100을 더합니다...
이 말인 즉, sap = 111, zap1 = 111이 됩니다... 맞죠?
그 다음에, zap2에서 또 sap변수를 인자로 사용하여 함수를 호출하게 됩니다...
그렇다는것은 sap이 또 증가하게 되어 112가 되죠...
sap과 zap1은 공유하는 사이잖아요?
결과적으로 zap1도 112가 됩니다...
그리고 마지막으로 sap 에 +1을 하게 되군요...
이 또한 공유하니...
sap과 zap1의 변수값에는 모두 113이 저장됩니다...
zap2 같은 경우에는 단순하게 22가 저장됨을 확인할 수 있습니다.
Ref()함수가 두번 호출되니
sap은 12가 되고 그 값을 zap2라는 int형 변수에 대입하는 것이니...
공유가 아닌 단지 값 대입이죠...
따라서 zap2에 20을 더해 단순히 22가 되는 것을 확인할 수 있습니다...
하하... 글로 풀어써서 어려워보이는데....
잘 읽어보시면서 한줄한줄 따라가보시면 금방 이해하실 것입니다...
여기서 그러면 조금... 더 꼬아볼까요?
반환형은 int형인데 이 반환된 값을 받을 변수가 레퍼런스형이라면 어떻게 될까요?
어렵죠...?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | int Ref(int &rsap) { rsap++; return rsap; } void main() { int sap = 10; int zap& = Ref(sap); } | cs |
이렇게 되면 어떻게 되느냐 이 말입니다... 하하...
레퍼런스형 변수는 변수의 메모리를 공유하죠... 그런데 저 함수에서는
상수를 반환하는 것이나 다를 것이 없기에...
논리에 맞지 않습니다... 따라서 이와 같은 반환값 저장은 옳지 않습니다....
와... 말이 굉장히 베베 꼬였습니다...
월요월요하니 이해해주시길....
요즘 블로그가 점점 막장이 되고 있군요....
하하...
하나 더 꼬아볼까요???
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | int Ref(int &rsap) { int num = 1; num + rsap; return num; } void main() { int sap = 10; int zap& = Ref(sap); } | cs |
요건 어찌 될까요...? Ref() 함수에서 만든 num이라는 지역변수를 반환하군요...
지역변수는 해당 함수가 끝나면 소멸되죠??
자... Ref 함수가 임무를 완료한다면... num은 자연스레 소멸됩니다...
그렇다면 레퍼런스 변수인 zap은... 뭘 공유하게 되나요...
이렇게도 쓰지 말라는 뜻에서.... 말씀드립니다... 하하...
아.... 나의 그림 그리는 도구들이 필요한데... 이쁘게 그림 그리면서 재미있는 포스팅을 하고 싶군요...
시간이 걸린다는 것이 함정이지만....
Input은 흘러 넘치는데 Output을 내보내는데 미친듯이 삽질을 하고 있는 삽잡이입니다...
글도 지금 보면... 삽질 같은.... 지렁이...
하하... 그래도... 길게 썼군....
월요월요 삽잡이입니다... 미쳐서 이렇게 쓰고 있나...
'삽질의 현장 > - C++' 카테고리의 다른 글
#025_시(c)시(c)해서 C++?!_멤버 이니셜라이저 (0) | 2015.07.23 |
---|---|
#024_시(c)시(c)해서 C++?!_UML 클래스 다이어그램 관계 (0) | 2015.07.21 |
#022_시(c)시(c)해서 C++?!_ 팩토리 패턴 사용해보기 (0) | 2015.07.20 |
#021_시(c)시(c)해서 C++?!_다시 한번 Command 패턴 사용하기 (0) | 2015.07.20 |
#020_시(c)시(c)해서 C++?!_ 되돌아보자 씨쁠쁠 ... (0) | 2015.07.18 |