C++ 에서 사용중인 namespace에 대해 알아보자 🙃

안녕하세요! 두두코딩 널두 🥸 입니다 ✋
오늘은 C++ namespace에 대해 알아보겠습니다.

🖇 소스코드에 마우스를 올리고 copy 버튼을 누를 경우 더 쉽게 복사할 수 있습니다!

궁금한 점, 보안점 남겨주시면 성실히 답변하겠습니다. 😁
+ 감상평 댓글로 남겨주시면 힘이됩니다. 🙇

Intro.

오늘 포스팅에서는 namespace의 필요성, namepsace 요소 접근방법에 대해 알아보겠습니다.

namespace 필요성

C++ namespcae은 C언어의 문제점을 해결하기 위해 탄생되었다.

C언어에서는 하나의 실행파일을 만드는데, 동일한 이름의 함수를 사용할 수 없었다.

예를들어, video와 audio를 수행하는 media 관리 실행파일이 있다고 해보자. video와 audio를 만드는 개발자가 달라, 초기화 하는 이름을 동일하게 init()으로 만들고 컴파일 할 경우 아래와 같은 에러를 만날 수 있다.

./audio.h:1:6: error: redefinition of 'init'
void init() {}
     ^
./video.h:1:6: note: previous definition is here
void init() {}

이와 같은 문제는 C언어에서 동일한 이름의 함수를 사용할 수 없기 때문에 발생한다.

C++에서는 이 문제를 해결하기위해, 기능별로 구별할 수 있는 namespace 개념을 추가했다.

#include <stdio.h>

// Audio 관련된 일은 여기서.
namespace Audio
{
	void init() {
		printf("Audio init\n");
	}
}

// Video 관련된 일은 여기서.
namespace Video
{
	void init() {
		printf("Video init\n");
	}
}

// namespace 포함되지 않을 경우 전역 space
// global namespace라고도 함.
void init()
{
	printf("System init!\n");
}

int main()
{
	init();
	Audio::init();
	Video::init();
}

위와 같이 namespace를 활용해 기능단위로 묶어 사용한다면 이름이 동일해도 충돌나지 않고 함수를 호출할 수 있다.

namespace의 이름 (e.g. Audio, Video)을 붙여 init()을 호출할 경우 특정 기능에 해당되는 함수가 호출되며, namespace가 없는경우 전역 스코프에 있는 함수를 찾아 호출한다.

namespace의 장점

정리해보자면, C++에서 사용하고 있는 namespace의 장점은 2가지이다.

🌱 프로그램의 기능을 연관된 코드로 묶어서 관리함.
🌱 함수 또는 변수 등의 이름충돌을 막을 수 있음.

namespace 요소 접근방법

namespace 요소 접근 방법은 Qualified name (완전한 이름), using declaration (using 선언), using directive (using 지시어) 를 활용한 3가지 방법이 있다.

아래의 예시를 통해 접근 방법을 알아보도록 하자.

// Audio namespace 내 있는 함수를 접근하는 방법을 알아보자.

#include <stdio.h>

namespace Audio
{
	void init() { printf("Audio init\n"); }
	void reset() { printf("Video init\n"); }
}

Qualified name (완전한 이름)

namespace의 이름을 적고, 함수를 쓰는 방법이다.

int main() {
	// 접근 방법 namespae::함수명
	Audio::init();
}

가장 안전한 방법으로, 통상 개발할 때 해당 방법을 활용한다.

using declaration (using 선언)

namespace 내 있는 특정함수는 namespace 없이 사용하도록 선언하는 것이다.

int main() {
	// 특정함수 using 선언!!!
	using Audio::init();

	// Audio 내 init() 호출
	init();

	// 에러..
	// 전역스코프에 선언된 친구도 없음.
	//  using 선언으로 init() 만 선언함.
	reset();
	// Audio::reset(); 이 친구만 호출 가능.
}

using 선언의 스코프는 선언한 함수 스코프이다. 함수 밖에서 선언할 경우 전역스코프이다.

using directive (using 지시어)

특정함수를 넘어 namespace에서 사용중인 모든 함수를 사용할 수 있도록 지시하는 방법이다.

int main() {
	// namespace Audio와 연관된 모든 함수는 해당 스코프에서 사용가능하도록 함.
	using namespace Audio;

	// 둘 다 에러없이 동작함.
	init();
	reset();
}

위와 같이 Audio namespace에 모든 함수를 접근할 수 있도록 using 지시어를 활용할 수 있다.

특정함수만 접근할 수 있는 것이 아니기 때문에 init, reset 모두 호출할 수 있다.

🤔 만약, 전역영역에 동일한 이름을 가진 init 함수가 있을 경우 어떻게 될까?

이름 충돌로 에러가 발생할 것이다

이를 해결하기 위해서는 아래와 같이 “난 전역의 init을 호출할 것이다.” 라는 구별표시 :: 를 꼭 작성 해줘야한다.

int main() {
	using namespace Audio;

	// Audio 내 init() 호출
	init();

	// 전역에 있는 init() 호출
	::init();
}

우리가 C++을 처음 배울 때, 귀찮으면 using namespace std 적고 시작해라. 라는 말을 많이 듣고 볼 수 있다. 그 이유가 위와 같이, std namespace에 있는 함수를 모두 사용할 수 있도록 하는 지시어이기 때문이다.

표준 라이브러리의 namespace는 이후 포스팅에서 자세히 다루고자 한다.

Outtro.

해당 포스팅은 Ecourse의 C++ Basic 강의를 참고해 작성되었습니다.

강의를 참고하실 분은 여기를 클릭해서 확인해주세요!