상세 컨텐츠

본문 제목

[TIL] 1 - 3. 객체지향 기본 문법 - 네임스페이스

언어/C++

by 민:하 2022. 2. 8. 01:42

본문

 

1. 네임스페이스 (namespace)의 개념

여러 가지 식별자(개발자가 이름지어줄 수 있는 것)들을 이름이 있는 범위로 그룹화하는 기법

  • 동일한 이름을 갖는 함수나 변수라도 서로 다른 네임스페이스안에 만들 수 있다.
  • 코드 내에서 이름이 같은 식별자나 라이브러리 사용하는 과정에서 생기는 식별자명 충돌 문제를 해결할 수 있다.
  • scope resolution operator( :: )를 사용하여 네임스페이스를 구분한다.
  • ex) A::input( )  B::input( )
  • 네임스페이스에서 정의된 함수와 변수는 네임스페잇 안에서 선언되어야 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/* a.h */
namespace a {
    extern int number; // extern 변수 선언
    void print(); // extern 함수 선언
}
 
/* b.h */
namespace b {
    extern int number; // extern 변수 선언
    void print(); // extern 함수 선언
}
 
/* a.cpp */
#include <iostream>
using namespace std;
namespace a {
    int number = 3; // extern 변수 정의
    void print() { // extern 함수 정의
        cout << "a print() number = " << number << endl;
    }
}
 
/* b.cpp */
#include <iostream>
using namespace std;
namespace b {
    int number = 7; // extern 변수 정의
    void print() { // extern 함수 정의
        cout << "b print() number = " << number << endl;
    }
}
 
/* main.cpp */
#include <iostream>
#include "a.h"
#include "b.h"
using namespace std;
int main(void) {
    cout << "main()에서 출력하는 a 네임스페이스의 number = " << a::number << endl;
    a::print();
 
    cout << "main()에서 출력하는 b 네임스페이스의 number = " << b::number << endl;
    b::print();
    return 0;
}
cs
  • namespace는 전처리기에 의해서 block 바깥에서 삽입. 즉, namespace에 있는 변수와 함수는 extern
  • extern의 범위는 전체 프로그램
  • extern 변수의 선언부에서 꼭 extern을 언급해야 함.
  • extern 함수의 선언부에서 extern 생략 가능. (우리가 main 함수 전에 함수 선언부를 쓸 때도 전부 extern 함수 선언)

 

< extern 변수의 선언 및 정의 >

  • extern 변수의 선언
    • 컴파일러에게 extern 변수에 대한 정보(type 정보)를 제공한다.
    • 초기화는 불가능하다.
    • 여러번 선언 가능하다. (각각의 파일에서 선언)
    • 선언 시 extern은 절대 생략 불가하다. (선언부가 정의부로 둔갑할 수 있기 때문)
  • extern 변수의 정의
    • 실제 메모리가 할당된다.
    • 초기화가 가능하다.
    • 전체 프로그램 내에서 딱 1회만 정의한다.
    • 블록 바깥에서 정의하며 extern은 생략 가능하다.

정리

- extern이 있는 초기화 구문 : 변수를 새로 정의하라는 의미 (메모리 할당해서 변수 정의)

- extern이 있고 초기화 없는 구문 : 다른 파일에 해당 이름의 변수가 있으면 가져다 쓰라는 의미. 없으면 0 초기화 )메모리 할당)

- 블록 외부에서 extern이 없는 초기화 구문 : 변수를 새로 정의 (메모리 할당)

- 블록 외부에서 extern이 없고 초기화도 없는 구문 : 변수를 새로 정의하고 0 초기화 (메모리 할당)

- 새롭게 변수를 메모리에 할당할 때 같은 이름의 extern 변수가 있는 경우 에러발생.

 

 

< extern 함수의 선언 및 정의 >

  • extern 함수의 선언
    • 컴파일러에게 extern 함수에 대한 정보를 제공한다.
    • 블록 외부에 있으면 자동으로 extern으로 인식하기 때문에 extern은 생략가능하다.
    • 한 프로그램, 여러 파일에서 사용하고자 하는 경우 각 파일마다 함수 선언을 해야한다.
  • extern 함수의 정의
    • 프로그램내의 위치 상관없이 어느 딱 한 곳에서만 정의되어 있기만 하면 된다.

2. using 지시자를 이용한 네임스페이스 활용

  • using 지시자 : 네임스페이스 내의 식별자를 네임스페이스명 없이 사용하기 위한 명령어
  • 빈번하게 사용되는 식별자를 미리 using해서 사용하면 편리
  • using 지시자를 사용해도 네임스페이스명과 함께 식별자를 사용해도 문제X 
    • using 네임스페이스명 :: 식별자명; : 네임스페이스 내의 하나의 식별자명만 바로 사용
    • using namespace 네임스페이스명; : 네임스페이스 내의 모든 식별자를 바로 사용

3. 네임스페이스의 중첩 사용

  • 네임스페이스 내에 다른 네임스페이스를 선언하여 사용할 수 있다.
  • 이때 범위결정 연산자( :: )를 두 번 연속 사용하게 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/* a.h */
namespace a {
    extern int number;
    int fuc();
}
 
/* b.h */
namespace b {
    extern int number;
    namespace inner {
        extern int number;
        int func();
}
 
/* a.cpp */
#include <iostream>
using namespace std;
namespace a {
    int number = 7;
    int func() {
        return number;
    }
}
 
/* b.cpp */
#include <iostream>
using namespace std;
namespace b {
    int number = 5;
    namespace inner {
        int number = 3;
        int func() {
            return number;
        }
    }
}
cs

4. 이름 없는 네임스페이스

  • 이름 없는 네임스페이스를 지정하면 그 내부에 바로 접근 가능
  • 이름 없는 네임스페이스내의 변수나 함수는 해당파일에서만 접근 가능 (C언어의 static 전역변수, static 함수 역할)
  • C++에서는 static 대신 이 방식을 자주 사용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
using std::cout;
using std::endl;
namespace {        // 해당 파일에서만 접근가능
    int number = 10;                 // extern 변수 정의부
    void func() {                    // extern 함수 정의부
        cout << "func" << endl;
    }
}
int main(void) {
    cout << number << endl;
    func();
    return 0;
}
cs

 

 


< 헤더파일에서 정의부 없이 선언부만 존재하는 이유 >

 

Linker가 a.obj와 b.obj를 링크하는 과정에서 하나만 존재해야 할 함수 정의부가 2개 있는 것을 발견

이중 정의로 인한 Link Error 발생

 

따라서, 헤더파일에는 선언부만 있는 것을 권장

(단, 하나의 파일만 사용할 경우는 상관 없음)

관련글 더보기

댓글 영역