본문 바로가기

컴퓨터공학/C, C++

C,C++> 네임 스페이스

네임 스페이스

 명칭과 충돌

명칭(Identifier)는 변수, 함수, 타입 등 다양한 요소를 정의할 때 사용한다. 

 

외부 라이브러리를 가져다 쓰다가 이름이 중복될 수 있다. 그러며 한쪽 라이브러리 사용을 포기해야 한다. 이런 문제를 방지하기 위해 네임 스페이스가 생겼다.

 

네입 스페이스(Name Space)는 명칭들이 기억되는 영역이며 명칭의 소속 공간이다. 이름을 담는 통이다. 1반과 2반 각각 밀하우스가 두 명이 있다면 두 학생의 소속은 다르기 때문에 호칭을 붙일 수 있어서 별 문제가 되지 않는다. 명칭도 마찬가지로 소속 네임 스페이스가 다르면 이름이 중복되어도 상관없다. 충돌 가능성이 있는 것을 네임 스페이스 안에 선언하는 게 좋다. 네임 스페이스를 정의하는 기본 공식은 다음과 같다.

 

namespace 이름 

{

여기에 변수나 함수를 선언한다.

}

 

네임 스페이스에 속한 명칭을 참조할 때는 :: 연산자 앞에 네임 스페이스 이름을 붙여 어디 소속인지 밝힌다. 

 

네임 스페이스를 별도 정의 하지 않아도 항상 존재하는 네임 스페이스가 있는데 전역 네임 스페이스라고 한다. 

디폴트 네임 스페이스라고 볼 수 있는데 흔히 전역 변수를 선언하는 영역, 함수 바깥쪽이 바로 이 영역이다.  원래부터 존재하므로 별도 이름은 없다. 

 

전역 네임 스페이스는 이름이 따로 없어서 :: 연산자만 사용한다. 

 

 

 

네임 스페이스 작성 규칙

1. 네임 스페이스도 일종의 명칭이라 다른 명칭과 중복되어서는 안된다.

2. 네임 스페이스는 전역 영역에 선언해야 한다. 

3. 네임 스페이스끼리 중첩 가능하다. 

4. 네임 스페이스는 여러 번 나누어 명칭을 선언할 수 있다. 

만약 네임 스페이스 A가 두 번 선언되면 두 번째 선언으로 교체되는게 아니라 기존 A 영역에 새로운 선언이 추가되어 병합된다. 네임 스페이스는 개방되어 있어서 여러 모듈에서 한 네임 스페이스에 필요한 명칭을 선언할 수 있다. 

5. 네임 스페이스가 이름이 없을 수 있다.

6. 다중 모듈 프로젝트에서 함수 본체를 어디에 작성할 건지 주의하자.

일반적으로 네임 스페이스에 변수나 함수 정의를 직접 하는 경우는 거의 없다.

헤더 파일의 네임 스페이스 안에 함수를 정의하면 헤더 파일을 인클루드할 때마다 개방성에 의해서 동일한 함수가 중복 생성될 것이다. 

선언은 여러 번 반복할 수 있지만 정의는 단 한 번만 해야 한다. 

 

 

네임 스페이스 사용

네임 스페이스는 명칭 선언 영역을 분리하여 충돌을 방지한다. 네임 스페이스 안에 명칭을 선언하면 이름을 붙일 때 충돌을 걱정하지 않고 자유롭게 이름을 붙일 수 있다. 그러나 이렇게 작성된 명칭을 사용하려면 매번 소속을 밝히고 참조해야 하므로 번거롭다. 

 

namespace MYNS {
	int value;
    double score;
    void func() { printf("dsfsdfsdf"); }
}

void main()
{
	MYNS::value = 3;
    MYNS::score = 1.2345;
    MYNS::func();
}

항상 네임 스페이스 이름을 붙여야 하는데 이름이 길어지면 가독성이 떨어진다. 

이런 불편함을 없앨 수 있는 세 가지 방법이 있다. 

 

 

using 지시자(Directive)

using namespace 다음에 네임 스페이스를 지정하는 방식이다. 

지정한 네입스페이스의 모든 명칭을 이 선언이 있는 영역으로 가져와 소속 지정없이 명칭을 바로 사용할 수 있도록 한다. 

#include <Turboc.h>

namespace MYNS {
	int value;
   	double score;
    void func { printf("dsfdsfsdf"); }
}

using namespace MYNS;
void main(){
	value = 3;
    score = 12.412;
    func();
}

using 지시자가 영향을 미치는 범위는 이 지시자가 있는 영역에 국한된다. 

특정 함수나 블록 안에 using 지시자를 사용하면 이 블록에서만 지정한 명칭을 바로 사용할 수 있다.

 

 

using 선언(Declaration)

using 지시자는 지정한 네임 스페이스의 모든 명칭을 가져오지만 using 선언은 하나의 명칭만 가져온다. 

위 예를 참조하자면

using MYNS::value;

라고 선언하면 value 변수만 소속을 밝힐 필요없이 바로 사용할 수 있다. 

 

 

using에 의한 충돌

소속을 밝히지 않고 사용하다 보니 이 영역에 이미 존재하는 명칭과 충돌할 수 있다. 

이럴 경우 지역 변수에 의해 가려진다. 전역 변수가 지역 변수에 가려지는 것과 동일하다.

 

 

생성자 활용

전역 객체는 프로그램과 함께 생성하므로 생성자가 main 함수보다 빨리 호출된다.

main 어떤 코드보다 실행 우선 순위가 높아서 초기화에 적합하다 .

 

 

초기화 순서

초기화 리스트의 초기식들은 리스트에 나타난 순서가 아니라 멤버의 선언 순서대로 실행된다. 

 

 

오버로딩과 오버라이딩

B::f(int), B::f(double) 함수가 있고 파생 클래스 D에서 D::f(char *)를 재정의하면 상속관계이므로 오버로딩이 안된다. 

D 함수가 정의되면 기반 클래스 함수들이 모두 가려진다. 

f(1)로 정수 인수를 주어도 상속받은 f(int)가 호출되지 않는다. 

그러나 가려진 것일 뿐 상속은 되므로 범위 연산자를 통해서 d.B::f(1), d.B::f(2.3)으로 호출하면 재정의된 f에 의해 가려진 부모 멤버 함수를 호출할 수 있다. 

오버로딩과 오버라이딩은 양립할 수 없기 때문에 상속받은 멤버 함수를 재정의할 때는 부모 멤버 함수와 같은 원형으로 재정의해야 한다. 

부모 멤버 함수를 그대로 상속받으면서 여기에 추가로 오버로딩할 수 없다.

기반 클래스에 여러 개 함수가 중복정의되어 있다면 이 함수들을 모두 재정의하거 아예 재정의하지 말아야 한다. 

하나만 재정의하면 이 함수에 원형이 다른 함수들은 모두 가려지기 때문이다. 

 

컴파일러는 오버로딩된 함수를 결정하기 위해 인수 타입을 검사한다. 이 과정에서 완전히 일치하는 함수가 없으면 암시적인 타입 변환을 통해 최대한 일치하는 함수를 찾는다. 여기에 상속 계층까지 고려하면 복잡하다. 

 

문법의 예외

부모 포인터가 자식 객체를 가리키는 건 안전하다. 하지만 예외가 존재한다. 부모 타입 포인터가 자식 타입 객체 배열을 가리킬 때 문제가 생긴다. 

 

void main() {
	Base arB[5];
    Derived arD[5];
    int i;
    Base *pB = arD;
    for (i = 0; i<5; i++){
    	pB->OutMessage();
        pB++;
    }
}

Base타입 포인터가 파생 클래스 배열 arD를 대입받았다. 

문제가 없다. 왜냐하면 파생 클래스는 부모 클래스 변수와 함수를 모두 갖고 있기 때문이다.

++연산자로 다음 객체를 이동할 때 문제가 생기는데 다음 객체로 이동할 정확한 위치를 찾지 못한다.

++ 연산자는 대상체 크기 만큼 이동하는데 부모 클래스와 자식 클래스 크기가 다르기 때문이다. 

 

using 선언

using 선언은 다른 네임 스페이스 명칭을 이 선언이 있는 곳으로 가져오는 문장이다. 

이것은 클래스 계층 사이에도 쓸 수 있다. 클래스 자체도 국지적인 네임 스페이스로 볼 수 있다.

using 선언으로 원하는 명칭을 가져올 수 있다. 

클래스에서 using 선언을 사용하면 기반 클래스 멤버의 액세스 속성을 원하는 대로 바꿀 수 있다. 

 

예를 들어 파생 클래스가 기반 클래스를 private 상속을 해도, using 선언으로 파생 클래스의 public 액세스 속성에 기반 클래스의 변수를 둔다면 이 변수는 public이 되어서 변경된 속성대로 액세스가 허가된다. 

 

'컴퓨터공학 > C, C++' 카테고리의 다른 글

C,C++> 타입 정보  (0) 2022.09.02
C,C++> 예외 처리  (0) 2022.09.01
C,C++> 템플릿  (0) 2022.08.31
C,C++> 다형성  (0) 2022.08.22
C,C++> 상속  (0) 2022.08.19