도순씨의 코딩일지

C++ :: 이름공간(namespace) 본문

𝐏𝐑𝐎𝐆𝐑𝐀𝐌𝐌𝐈𝐍𝐆/𝐂++

C++ :: 이름공간(namespace)

도순씨 2020. 7. 22. 21:42

이미 언어를 여러 개 익힌 뒤라 그런지 모르겠지만 대충 내용을 훑어보면 어떤 내용일지 예상이 간다. 그런데 이번에 살펴본 이름공간은 (나에게는) 너무나도 생소한 개념이었다. 

 

이름공간은 이름의 충돌을 막기 위한 것이다. 다음 코드를 통해서 살펴보도록 하자. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
 
void SimpleFunc(void){
    std::cout<<"BestCom이 정의한 함수"<<std::endl;
}
 
void SimpleFunc(void){
    std::cout<<"ProgCom이 정의한 함수"<<std::endl;
}
 
int main(void){
    SimpleFunc();
    return 0;
}
cs

이 코드는 애초에 바르지 않은 코드라는 것을 눈치챌 수 있다. 똑같은 이름, 똑같은 매개변수이므로 함수 오버로딩에도 해당되지 않는다(cf. 함수 오버로딩은 똑같은 이름, 다른 매개변수) 컴파일러에서도 빨간 줄로 이 코드가 틀렸음을 알려줄 것이다. 

하지만 이름공간을 사용하면 이런 문제를 해결할 수 있다.

 

@ 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
 
namespace BestComImpl{
    void SimpleFunc(void){
        std::cout<<"BestCom이 정의한 함수"<<std::endl;
    }
}
 
namespace ProgComImpl{
    void SimpleFunc(void){
        std::cout<<"ProgCom이 정의한 함수"<<std::endl;
    }
}
 
int main(void){
    BestComImpl::SimpleFunc();
    ProgComImpl::SimpleFunc();
    return 0;
}
cs

 

 

@ 실행 결과

1
2
BestCom이 정의한 함수
ProgCom이 정의한 함수
cs

 

이름 공간을 먼저 선언하고 그 안에서 함수를 선언해주었다.

C++에서 :: 는 범위 지정 연산자이다. 위의 코드에서 BestComImpl::SimpleFunc()을 예시로 들면 BestComImpl이라는 이름 공간으로 범위를 지정해주고 그 안에 SimpleFunc() 함수를 실행하도록 하는 것이다.

 

함수의 선언과 정의를 구분하고자 한다면 다음과 같이 표시할 수 있다. 

 

@ 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
 
namespace BestComImpl{
    void SimpleFunc(void);
}
 
namespace ProgComImpl{
    void SimpleFunc(void);
}
 
int main(void){
    BestComImpl::SimpleFunc();
    ProgComImpl::SimpleFunc();
    return 0;
}
 
void BestComImpl::SimpleFunc(void){
    std::cout<<"BestCom이 정의한 함수"<<std::endl;
}
 
void ProgComImpl::SimpleFunc(void){
    std::cout<<"ProgCom이 정의한 함수"<<std::endl;
}
cs

 

@ 실행 결과

 

1
2
BestCom이 정의한 함수
ProgCom이 정의한 함수
cs

 

참고로 동일한 이름공간에 정의된 함수를 호출할 때는 이름 공간을 명시할 필요가 없다. 단, 다른 이름 공간에 정의된 함수를 호출할 때는 이름공간을 꼭 작성해주어야 한다. 이름 공간의 중첩 또한 가능하다. 

 

그렇다면 우리가 습관적으로 사용해왔던 std::cout, std::cin, std::endl은 무슨 의미를 담고 있을까? std라는 이름 공간에 선언된 cout, std에 선언된 cin, std에 선언된 endl이다. 헤더파일 <iostream>의 이름공간 std안에 cout, cin, endl이 선언되어 있는 것이다.

 

하지만 이름공간을 계속 선언하는 것은 불편하다. 다음의 코드를 통해 이 불편함을 해결해보도록 하자.

 

@ 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
 
namespace Hybrid{
    void HybFunc(void){
        std::cout<<"So simple function!"<<std::endl;
        std::cout<<"In namespace Hybrid!"<<std::endl;
    }
}
 
int main(void){
    using Hybrid::HybFunc;
    HybFunc();
    return 0;
}
cs

 

@ 실행 결과

1
2
So simple function!
In namespace Hybrid!
cs

 

using Hybrid::HybFunc 은 이름 공간 Hybrid에서 HybFunc을 찾으라는 의미와 같다. HybFunc은 항상 함수의 이름이여야 하는 것이 아니다. 변수의 이름이 될 수도 있다. 또한 지역 변수의 선언 개념과 비슷하게 선언된 지역을 벗어나면 효력을 잃게 된다.

 

using namespace std를 선언할 수도 있다.

 

@ 코드

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
 
using namespace std;
 
int main(void){
    int num = 20;
    cout<<"Hello World!"<<endl;
    cout<<"Hello "<<"World!"<<endl;
    cout<<num<<' ' <<'A';
    cout<<' '<<3.14<<endl;
    return 0;
}
cs

 

@ 실행 결과

1
2
3
Hello World!
Hello World!
20 A 3.14
cs

 

이러한 방법이 편리해보이긴 하지만 이름 충돌을 발생할 가능성이 있으므로 적절하게 사용하는 자세가 필요하다.

 

앞에서 범위지정 연산자 :: 을 살펴보았다. 범위지정 연산자는 또 다른 기능이 있다. 바로 지역 변수 안에서 전역 변수를 가리키는 역할이다. 

Comments