C++ 이름공간, 참조자!
이름공간(namespace)
개발 편의성을 위해 사용, 같은 이름, 같은 형, 같은 인자 개수 함수도 이름공간이 다르면 구분해서 사용 가능.
namespace FirstNameSpace
{
void SimpleFunc()
{
std::cout<<FirstNameSpace SimpleFunc<<std::endl;
}
}
namespace SecondNameSpace
{
void SimpleFunc()
{
std::cout<<SecondNameSpace SimpleFunc<<std::endl;
}
}
int main()
{
FirstNameSpace::SimpleFunc();
SecondNameSpace::SimpleFunc();
//함수 이름, 매개변수 개수, 변수 형 모두 같은 상황이지만 이름 공간이 다르기 때문에 OK
return 0;
}
사용하는 이유는 여러 개발자가 협업 하면서 개발하다 보면 함수가 서로 비슷해서 겹치는 경우가 생기는데 이를 해결하기 위해서 라고…..
사용되는 ::
을 cout
이나 cin
을 사용할때 많이 보았다.
배운것 처럼 cout, cin, endl과 같은 객체들이 std라는 namespace안에 있기 때문.
using을 사용하면 귀찮은 ::
을 안써도 된다.
#inlcude <iostream>
using std::cin;
using std::cout;
using std::endl;
using FirstNameSpace::SimpleFunc;
//using을 사용해서 다음부터 함수 호출 할땐 이름공간 없이 호출!
namespace FirstNameSpace
{
void SimpleFunc()
{
...
}
}
int main()
{
cout<<"Hello wolrd!"<<endl;
//귀찮은 std 이름공간 생략
SimpleFunc();
//SimpleFunc가 소속된 이름공간도 생략
return 0;
}
#inlcude <iostream>
using namespace std;
int main()
{
cout<<"Hello wolrd!"<<endl;
return 0;
}
참조자(Reference)
C++에서 사용되는 포인터와 비슷한 녀석
int num1=10;
int *ptr1=num1; //c에서 사용하는 포인터
int &num2=num1; //이녀석이 참조자
//c에서는 볼수 없던 형식, num1에 num2라는 별명을 지어준 샘이다.
참조자는 변수와 똑같이 작동하기 때문에 변수라고 봐도 무방함.
참조자는 상수, NULL, 초기참조 대상없이는 선언 불가능. 아래처럼 하면 오류난다.
int &ref1=10;
int &ref1=NULL;
int &ref1;
c에서 call by value, call by reference 라고 들어 보았을 것인다,
함수의 매개변수가 변수 값만 받아 사용하느냐, 변수 주소값을 받아 값의 변경까지 할 수 있게 하는냐 차이다.
c++에선 포인터를 사용해 똑같이 할 수 있지만 참조자를 통해서도 할 수 있다.
void SwapByAddr(int *ptr1, int* ptr2)
{
int temp=*ptr1;
*ptr1=*ptr2;
*ptr2=temp;
}
void SwapByRef(int &ref1, int &ref2)
{
int temp=ref1;
ref1=ref2;
ref2=temp;
} //그냥 변수처럼 사용하면 되서 편하다.
int main()
{
int num1=10;
int num2=20;
SwapByRef(num1, num2);
}
ref1이 num1의 10을 받아서 연산하는 것이 아니라 num1자체를 받기 때문에 교환이 이루어짐. 애초에 참조자는 상수 초기화가 안된다.
참조자도 물론 단점이 있다.
...
HappyFunc(num);
printf("%d", num);
...
C에서 위와같이 사용했다면 num이 어떤 변수인진 모르지만 HappyFunc
안에서 num값이 변경 되지 않았다고 확실히 말 할 수 있다. 하지만 C++에선 아니다.
void HappyFunc(int &ref); //함수 선언문
...
int num;
HappyFunc(num); //num값이 안에서 바뀔수도 있음.
HappyFun
c의 매개변수가 참조자로 선언되어있어 num값이 함수 안에서 변경 되지 않는지 확신할 수 없다.
개발하다 num값이 이상해 어디서 변경되는지 확일할 때 HappyFunc
같이 선언된 함수가 있다면 함수 안을 모두 살펴 보아야 한다.
다행히 const
를 사용하면 함수 안까지는 살펴보지 않아도 함수안에서 num이 변경되는지 안되는지 확인 할 수 있다.
void HappyFunc(const int &ref);
//선언부만 보고 num이 벼경되지 않음을 확신
...
int num;
HappyFunc(num);
함수 원형을 보고 const
를 확인하였기 때문에 HappyFunc
안에서 num이 변경되지 않음을 확신할 수 있다.
반환형이 참조자일 경우
반환을 받은 변수에 따라 어떤 값이 저장될지 달라진다.
int& RefReturnFuncOne(int &ref)
{
ref++;
return ref;
}
int RefReturnFuncTwo(int &ref)
{
ref++;
return ref;
}
int main()
{
int num=1;
int &num2=RefReturnFuncOne(num1);
num1++;
num2++;
//num1과 num2는 모두 같은 주소위치를 가르키고 있고 값은 4.
int num3=1;
int num4=RefReturnFuncOne(num3);
num3++;
num4+=100;
//num4는 그저 int형 변수이기 때문에 num3은 참조값(주소)가 아닌 정수값을 반환받음.
//num3은 3, num4는 102가됨.
}
RefReturnFuncTwo
의 경우 반환형이 int
형이기 애초에 반환값이 참조값(주소) 아닌 참조자의 값이 된다.
int &num=RefReturnFuncTwo(temp);
참조자는 상수참조자 안되기 때문에 위처럼 사용하면 컴파일 오류발생.
~생성된 임시변수를 참조하는 방식으로 가능할 줄 알았는데 어차피 임시변수는 사라지고 값만 남기 때문에 상수취급 해서 안되나봄….~
const 참조자
참조자가 상수를 참조 못한다 하였지만 const
키워드를 사용하면 사실 된다….
...
int main()
{
const int num1=10;
int &ref1=num1; //num을 상수취급 해서 오류발생
const int num2=10;
const int &ref2=num2; //const키워드로 참조 가능
const int &ref3=10; // 이것도 가능
}
10이라는 상수(리터럴상수)도 컴퓨터 특정 주소에 저장된 값이다.
다음행으로 넘어가는 순간 이 주소안의 값은 쓰레기값으로 변한다(언제든지 덮혀씌어질 수 있음).
굳이 참조까지 하면서 유지 시키려는 이류는 다음과 같다.
int Adder(const int &num1, const int &num2)
{
return num1+num2;
}
...
cout<<Adder(3,4)<<endl;
상수도 넘기고 변수도 넘기고!