C++ 표준은 이름 사용 범위를 더 잘 제어할 수 있도록 '이름공간'이라는 기능을 제공합니다.
최신의 이름공간을 배우기 전에, C++가 이미 가지고 있었던 이름 공간 기능을 간단하게 설명해보겠습니다.
구식 이름 공간
선언 영역(declarative region)
선언을 할 수 있는 영역입니다. 전역 변수의 선언 영역은 선언된 파일이고 지역변수의 선언 영역은 선언된 블록입니다.
잠재 사용 범위(potential scope)
선언한 지점부터 선언 영역의 끝까지를 잠재 사용 범위라고 말합니다.
잠재 사용 범위는 선언 영역에 비해 좁습니다.
말 그대로 잠재 사용 범위는 해당 변수의 사용이 가능한 범위를 말합니다.
사용 범위는 해당 변수에 접근(읽기/쓰기)을 한 범위입니다.
이것은 지역변수에 대해 공부를 하셨으면 쉽게 이해가 가능한 용어입니다.
최신 C++에서의 이름공간
새로운 종류의 선언 영역을 정의함으로써 이름이 명명된 이름 공간을 만들 수 있는 기능이 C++에 새로 추가되었습니다.
목적은 이름을 선언하는 영역을 따로 제공하는 것입니다.
하나의 이름공간에 속한 이름은 다른 이름공간에 속한 이름과 충돌하지 않습니다.
사용하려면 namespace라는 키워드를 사용하면 됩니다.
이름공간의 필요성
이름 공간이 왜 필요한가에 대해 의문점을 가질 수 있습니다.
먼저 예시를 하나 들어보겠습니다.
구글사의 라이브러리, 애플사의 라이브러리를 사용하는데 둘 다 똑같은 이름을 가지고 있는 함수가 있다고 가정합시다.
이 함수의 이름은 Display입니다.
이름 공간이 나오기 전 C++은 충돌 문제가 생길 것입니다.
하지만 이름 공간이 나오고 나서는 이 문제가 해결되었습니다.
#include <iostream>
namespace Google {
void Display();
}
namespace Apple {
void Display();
}
int main(void) {
Google::Display();
Apple::Display();
}
이름 공간 내부에 접근하려면 ::연산자(범위 확인 연산자라고 부름.)를 사용하시면 됩니다.
Google::Display();처럼 이름 공간이 지정된 이름을 제한된 이름(qualified name)이라고 합니다.
using
C++ 이름 공간을 보다 간편하게 사용할 수 있도록 두 가지 방법을 제공합니다.
- 선언
- 지시자
선언은 하나의 특별한 식별자를 사용할 수 있게 만듭니다.
지시자는 그 이름 공간 전체에 접근할 수 있게 만듭니다.
선언
namespace Google {
void Display();
}
using Google::Display;
제한된 이름 앞에 using을 붙여주면 됩니다.
using 선언을 하게 되면 ::연산자로 접근을 하지 않아도 Display();만 써도 접근이 가능하게 됩니다.
마치 우리가
using namespace std;
하는 거랑 동일한 효과입니다.
안 써주면
std::cout << "Hello World";
이렇게 써야 합니다.
단점은 using 선언을 하게 되면 동일한 이름으로 선언을 못합니다.
#include <iostream>
namespace Google {
int num = 0;
}
int main(void) {
using Google::num;
int num = -1;
printf("%d", num);
}
VS(Visual Studio) 기준으로 재정의를 했다고 컴파일 에러가 발생합니다.
using은 변수와 마찬가지로 선언 영역에서만 그 효과가 발생합니다.
#include <iostream>
namespace Google {
int num = 0;
}
int num = -1;
int main(void) {
using Google::num;
printf("%d",::num);
}
using Google::num 때문에 전역 변수 num이 가려지게 되고 num의 대상은 Google이라는 이름공간 안에 있는 num이 됩니다.
전역에 있는 변수(num)에 접근하고 싶다면 ::연산자를 사용하면 됩니다.
지시자
지시자는 해당 이름공간에 속한 모든 이름을 ::연산자를 사용하지 않고도 가능케합니다.
사용방법은 선언과 비슷하면서도 간단합니다.
선언과의 차이점은 "하나의 이름"이고 지시자는 "하나의 이름공간"입니다.
using namespace Google;
선언과는 다르게 using뒤에 namespace라는 키워드가 붙었습니다.
#include <iostream>
namespace Google {
int num = 0;
double num2 = 123.11;
}
int main(void) {
using namespace Google;
printf("%d",num);
printf("%f", num2);
}
이처럼 지시자는 해당 이름공간의 모든 이름을 ::연산자 없이 사용이 가능합니다.
이름공간은 중첩도 가능하다.
namespace Google {
namespace A {
int a = 0;
}
int num = 0;
double num2 = 123.11;
}
이름공간 내에 또 다른 이름공간이 존재할 수 있으며 접근도 마찬가지로 ::연산자로 접근합니다.
이름공간에 이름이 없을 때
#include <iostream>
namespace {
namespace A {
int a = 0;
}
int num = 0;
double num2 = 123.11;
}
int main(void) {
printf("%d",num);
printf("%f", num2);
}
이름공간의 이름이 없을 수도 있습니다.
이 경우에는 using이 있는 것처럼 동작하게 됩니다. 즉,::연산자로 접근을 안 해도 됩니다.
이름공간은 선언한 파일 외에서 사용이 불가능합니다.
댓글