[C++]이름공간에 대한 소개, 문제 01-4

서희찬·2021년 4월 28일
post-thumbnail

이름공간은 "이름을 붙여놓은 공간"이라고 얘기 할수있다.
말 그대로 특정 영역에 이름을 붙여주기 위한 문법적 요소이다.

이름공간의 등장배경

A,B,C회사가 합동 프로젝트를 진행하기로 하고 파트별로 코드를짠 후 6개월 후에 모였는데!
아뿔싸!! 겹치는 함수가 상당수가 있다.
이는 프로그램을 쏴아악 뜯어 고쳐야할만큼 큰문제다!!!
그래서 이름공간이라는 것이 등장했다!!

이름공간의 기본원리

한 집에 철수라는 이름 두명이 산다면 철수야!! 부르면 누굴 부르는지 알 수 없다.
그러므로 다른집 201호 철수, 202호 철수 이렇게 구분 해주면
"202호 철수!!" 라고 부르면 구분할수 있다!!

이것이 이름공간의 기본원리이다.
그럼 바로 코드를 보자.

이렇듯

namspace BestComImp1 // bestComImp1의 이름공간의 이름 
{
// 이름 공간 내부 
}

이렇게 이름공간을 만들고 내부에 함수를 정의하면 이름 충돌이 발생하지 않는다.

메인 함수의 :: 연산자를 가리켜 "범위지정 연산자"라 하며, 그 이름이 의미하듯 이름공간을 지정할 때 사용하는 연산자이다.

#include <iostream>

namespace Best {
    void SimpleFunc(void)
    {
        std::cout<<"Best 가 정의한 함수"<<std::endl;
    }
}

namespace est {
    void SimpleFunc(void)
    {
        std::cout<<"est 가 정의한 함수"<<std::endl;
    }
}

int main(void)
{
    Best :: SimpleFunc();
    est :: SimpleFunc();
    
    return 0;
}

이름공간 기반의 함수 선언과 정의 구분

함수의 선언과 정의를 분리하는것이 일반적이다!
그렇다면 이름공간 기반에서 함수의 선언과 정의를 구분하는 방법은 무엇일까?

이렇다!
참고로 동일한 이름공간안에 있는 함수를 호출할때에는 이름공간을 명시할 필요가 없다.

이름공간의 중첩

이와 같이 이름공간안에 이름공간이 삽입될 수 있다.
총 3개의 num이 존재하는데

std::cout<<Parent::num<<std::endl;
std::cout<<Parent::SubOne::num<<std::endl;
std::cout<<Parent::SubTwo::num<<std::endl;

는 순서대로 2,3,4 가 출력된다.

문제 01-4

NameSp2.cpp 를
헤더,소스,메인파일로 분리해라!

name.hpp

//
//  name.hpp
//  1_practice
//
//  Created by 서희찬 on 2021/04/28.
//

#ifndef name_hpp
#define name_hpp

namespace Best {
    void SimpleFunc(void);
}

namespace est {
    void SimpleFunc(void);
}

#endif /* name_hpp */

name.cpp

//
//  name.cpp
//  1_practice
//
//  Created by 서희찬 on 2021/04/28.
//
#include <iostream>
#include "name.hpp"

void Best::SimpleFunc(void)
{
    std::cout<<"Best 가 정의한 함수"<<std::endl;
}

void est::SimpleFunc(void)
{
    std::cout<<"est 가 정의한 함수"<<std::endl;
}

main.cpp

#include <iostream>
#include "name.hpp"


int main(void)
{
    Best :: SimpleFunc();
    est :: SimpleFunc();
    
    return 0;
}

자구를 하고 온 나에겐 너무 익숙해져버린 분리닷

std::cout, std::cin,std::endl

우리는 이것의 정확한 정체는 모르지만 이때까지 사용해왔다!
하지만 :: 을 배운 이상!
우리는 좀 더 이 친구들의 정체를 알 수 있다.

  • std::cout -> "이름공간 std에 선언된 cout"
  • std::cin -> "이름공간 std에 선언된 cin"
  • std::endl -> "이름공간 std에 선언된 endl"

이렇듯 우리는 이름공간 std에 cout,endl,cin 이 선언되어 있다는 결론을 내릴 수 있다.
이름 충돌을 막기위해서 C++표준에서 제공하는 다양한 요소들은 이름공간 std 안에 선언되어있다.

using을 이용한 이름공간의 명시

이제 ciut,cin,endl 등등을 참조할 때마다 std:: 를 앞에 붙여한다는것을 배웠지만 !
이것이 여간 귀찮지 않다는 생각이든다!
그러나!!!!
추가적인 선언 하나만으로도 이 불편을 해소할 수 있다.

다음 예제를 보자!

#include <iostream>

namespace Hybrid {
    void HybFunc(void)
{
    std::cout<<"So simple Funciton! "<<std::endl;
    std::cout<<"In namespace Hybrid!"<<std::endl;
}
}

int main(void)
{
    using Hybrid::HybFunc;
    HybFunc();
    return 0;
}

using Hybrid::Hyfunc;
은 "Hyfunc를 이름 공간 Hybrid 에서 찾으라" 라는 선언이다!!!

그리고 위에서는 메인함수내에서 선언되어 이 함수안에서만 효력을 가지게 된다.
프로그램 전체영역에 효력을 미치게 할려면 전역변수와 마찬가지로 함수밖에 선언 하면된다.

그럼 밖에 선언한 다음예제를 보자!

#include <iostream>

using std::cin;
using std::cout;
using std::endl;

int main(void)
{
    int num2;
    int num = 20;
    cout<<"Hello World"<<endl;
    cout<<"Hello"<<"World"<<endl;
    cout<<num<<" "<<"A";
    cout<<" "<<3.14<<endl;
    cout<<"num2 : ";
    cin>>num2;
    
    
    return 0;
}


이렇게 일일이 using 선언이 귀찮다면 "이름 공간 std에 선어된 모든 것에 대해 이름공간 지정의 생략"을 명령할 수 있다.

using namespace std;

이는 이름 공간 std에 선언된 모든 것에 접근할때에는 이름공간의 지정을 생략하겠다는 말이다!!

그럼 다음예제를 보자 !

#include <iostream>

using namespace std;
int main(void)
{
    int num2;
    int num = 20;
    cout<<"Hello World"<<endl;
    cout<<"Hello"<<"World"<<endl;
    cout<<num<<" "<<"A";
    cout<<" "<<3.14<<endl;
    cout<<"num2 : ";
    cin>>num2;
    
    
    return 0;
}

동일하게 실행된다!

이름공간의 별칭 지정


이런식으로 이름공간이 너무~ 많아지면

AAA::BBB::CCC::num1=30;
AAA::BBB::CCC::num2=20;

와 같이 접근 하는 경우 매우 불편하고 폼도 안난다!
그런데 이를

namespace ABC = AAA::BBB::CCC;

와 같이 주면

ABC::num1 = 10;
ABC::num2 = 20;

와 같이 접근 가능하다!!

범위지정 연산자의 또 다른 기능

지역변수의 이름이 전역변수의 이름과 같은 경우,
전역변수는 지역변수에 의해 가려진다는 특징을 기억하는가!?

다음 코드르 보자

int val = 10; // 전역변수

int Simple(void){
	int val = 20; // 지역변수
    val += 3; // 지역 변수 val의 값 3증가
}

이 경우 전역변수 val에 접근하기 위해서는 어떻게 해야할까?

이때에도

범위 지정 연산자

를 사용하면 된다!!!

int val = 10; // 전역변수

int Simple(void){
	int val = 20; // 지역변수	
        val += 3; // 지역 변수 val의 값 3증
    	::val += 3; // 전역 변수 val의 값 3증가
}

그럼 이로써 Chapter1에 대한 이론적인 설명을 끝내겠다!!

다음 포스트에서는 프로젝트 하나를 보자

profile
Carnegie Mellon University Robotics Institute | Research Associate | Developing For Our Lives, 세상에 기여하는 삶을 살고자 개발하고 있습니다

0개의 댓글