1.1 이름공간(namespace)의 사용
'namespace' 키워드를 통해 고유의 'field'를 생성하는 개념이다.
예를 들어 영어영문학과 김소연과 외교학과 김소연이 같은 술집에 있다고 해보자. 술집에서 김소연을 부르면 아마 둘다 쳐다보게 될 것이다.
따라서 우리는 코드 상에서 이런 데이터 충돌을 방지하기 위해 'namespace' 키워드를 사용한다.
namespace English{
char Kim[1000] = "Department of English Language and Literature";
}
namespace Diplomacy{
char Kim[1000] = "Department of Diplomacy";
}
그럼 어떻게 English와 Diplomacy 안에 정의되어있는 Property에 접근할 수 있을까? 여기서 필요한 것이 바로 범위지정연산자 ' :: '이다.
그런데 이 키워드를 처음 본 것이 아닐 것이다. 우리는 입출력을 위해
std::cout, std::endl와 같은 키워드를 사용하였다.
std::cout<<"contents"<<std::endl;
std::cout<<English::Kim;
1.2 Using 키워드 사용
using namespace std;
#include <iostream>
using namespace std;
using namespace English;
namespace English{
char Kim[1000] = "Department of English Language and Literature";
}
namespace Diplomacy{
char Kim[1000] = "Department of Diplomacy";
}
int main(void){
cout<<Kim<<endl;
}
2.1 참조자(Reference)
참조자(Reference)는 C++을 처음 공부하는 나한테 굉장히 생소한 키워드였다. 그 성격은 C의 포인터와 유사하지만 그 쓰임이나 활용 형태가 달라 집중해서 보아야했다.
참조자는 보통 '별명'이라고 많이 부른다. 성격과 성질은 그대로인 또 다른 이름인 것이다. 사과를 apple이라고 부르는 것 처럼.
#include <iostream>
using namespace std;
int main(void){
int val = 10;
int &val2 = val; // (타입)(참조자_이름) = (참조할 변수);
cout<<val<<endl;
cout<<val2<<endl;
return 0;
}
cout<<"val의 값: "<<val<<endl;
cout<<"val2의 값: "<<val2<<endl;
cout<<"val의 주소: "<<&val<<endl;
cout<<"val2의 주소: "<<&val2<<endl;
val의 값: 10
val2의 값: 10
val의 주소: 0x61ff08
val2의 주소: 0x61ff08
2.2 참조자(Reference)와 포인터(Pointer)
#include <iostream>
using namespace std;
int main(void){
int num = 20;
int *ptr = #
int**dptr = &ptr;
// 변수 'num'의 주소값은 포인터 ptr에 저장,
// 포인터'ptr'의 주소는 더블포인터 dptr에 저장
int &ref = num;
int *(&pref) = ptr;
int **(&dpref) = dptr;
/**
* 변수 'num'의 또다른 이름 참조자 'ref'
*
* 참조자의 주소를 담는 참조자 포인터 pref에 num의
* 위치를 저장하고 있는 ptr 대입 -> ptr = pref
*
* 참조자의 주소가 담겨있는 그 주소를 참조하는 참조자
* 더블포인터 dpref에 ptr의 위치를 저장하고
* 있는 dptr대입 -> dptr = dpref
*
*/
cout<<ref<<endl;
cout<<*pref<<endl;
cout<<**dpref;
return 0;
}
2.3 참조자와 함수
#include <iostream>
using namespace std;
void swap(int &ref1, int &ref2){
int temp = ref1;
ref1 = ref2;
ref2 = temp;
}
int main(void){
int num1 = 10;
int num2 = 20;
swap(num1, num2);
cout<<"num1 = "<<num1<<endl;
cout<<"num2 = "<<num2<<endl;
return 0;
}
처음 이 코드를 보았을 때 의문이 들었던건 swap 함수는 참조자를 매개변수로 하는 함수인데 main함수에서 왜 인자로 넘겨줄때 일반 정수변수를 넘겨줄까?였다.
참조자를 매개변수로 하는 함수에 저렇게 일반 변수를 던져주게 되면 그 동시에 ref1과 ref2는 각각 num1, num2의 참조자로 초기화 된다.
그렇다면 다른 변수로 또 swap함수를 호출하면 어떻게 될까가 궁금했다.
다른 두 변수에 같은 참조자가 붙는건 말이 안되기 때문이다. 한 포인터가 두 개의 property를 참조할 수 없는 것 처럼.
#include <iostream>
using namespace std;
void swap(int &ref1, int &ref2){
int temp = ref1;
ref1 = ref2;
ref2 = temp;
}
int main(void){
int num1 = 10;
int num2 = 20;
swap(num1, num2);
cout<<"num1 = "<<num1<<endl;
cout<<"num2 = "<<num2<<endl;
int num3 = 99;
int num4 = 100;
swap(num3, num4);
cout<<"num3 = "<<num3<<endl;
cout<<"num4 = "<<num4<<endl;
return 0;
}
swap 함수에 breakpoint를 걸고 디버그해서 ref1과 ref2를 관찰해봤는데 num1,2,3,4 전부 값 교환이 정상적으로 이루어졌다.
따라서 매개변수로 참조자가 있으면 인자를 던져줄 때 해당 인자의 참조자가 된다기보단 일시적으로 참조자가 된다는 표현이 맞는 것 같다.
포인터를 사용하지 않고 call-by-reference를 구현할 수 있는 방법?이 적당한 표현인 것 같다.
2.4 반환형이 참조자인 경우
#include <iostream>
using namespace std;
int& incNum(int &ref){
ref ++;
return ref;
}
int main(void){
int num1 = 10;
int &num2 = incNum(num1);
num1 += 2;
num2 += 3;
cout<<"num1 = "<<num1<<endl;
cout<<"num2 = "<<num2<<endl;
return 0;
}
int &num2 = incNum(num1);
