보통 초보들이 제법 구조를 갖춘 소스코드들을 보면서 당황하게 되는 것이,

난생 처음 보는 장황한 이름들에 당혹감을 느끼기 때문일듯 하다.

어디까지가 이름인지 어디까지가 연산인지도 구별하기 힘들지도.

그래서 까막눈을 트이게 해 주기 위해 먼저 코드 읽는 법을 설명해 주려 한다.

그러기 위해선 "왜? 이렇게 표기해야 하는가" 또한 설명되어야 겠지.



함수의 다형성 ( Polymorphism )

이름은 거창하지만 함수의 이름에 대한 재사용성을 높이기 위한 것이다.


1.  이게 없던 시절엔 이렇게 코딩해야 했다.

    print_char( char )

    print_int( int )


동어 반복아닌가? 이런건 좋지 않다.


2.  다형성이 지원되고 부터 다음의 표현이 가능해졌다.

    print( char )

    print( int )


같은 이름으로 함수를 불러도 전달한 인자의 타입에 따라 어떤 함수가 실행될지 결정 되는 것.

굿~


사실 별거 없고

컴파일러가 내부적으로 만들어 내는 함수의 이름에 인자의 타입의 접미사를 자동으로 붙여준다고 생각하면 된다.

( 즉 내부적으론 1의 예시대로 만들어지는 셈 )


하지만 리턴타입으로는 구별이 되지 않는다. 때때로 아쉽지만 때때로 편하다.



namespace

폴더 개념을 떠올리면 된다.

같은 이름을 가진 파일이 같은 폴더에 두 개 이상 존재할 수 없는 것 처럼,

충돌을 피하기 위해서는 이름을 바꾸든 다른 폴더에 배치하는 방법 밖에 없는데,

여러개의 이름을 바꾸려면 당연히 불편하다. ( 폴더를 만들고 집어 넣어버리는게 상책 )


이럴 때 그냥 namespace 로 싸 주면된다.


가령 어떤 똘똘한 프갤 루키가 코세에게 알고리즘 성능 최적화로 도전을 했다 치자.

두 사람이 구현한 strlen 함수 따위가 공교롭게도 이름이 겹친다.


namespace cose

{

    std::size_t strlen( const char* str )

    {

    ...

    }

};


namespace rookie

{

    std::size_t strlen( const char* str )

    {

    ...

    }

};


이렇게 해주면 C-Library 에 내장된 strlen 과 다음과 같이 구별된다.

( 앞으로 그냥 clib 라고 부르겠다 )


strlen( str );         // clib 의 strlen 을 호출

cose::strlen( str );   // 설명 안해도 알겠쥬?

rookie::strlen( str );


여기서 :: 를 scope 연산자 라고 부른다. 파일의 경로를 나눌 때 사용하는 / 랑 같은 의미다.

도스 콘솔창에서 파일을 복사하고 실행하고 하는 작업을 해보면,

매번 경로명을 다 붙이는게 불편해서 현재 경로를 이동시키고 싶을 때가 있고,

그냥 path 를 지정해서 지정된 디렉토리에서 자동으로 찾고 싶을 때가 있다.

그런 용도로 사용하는 것은


using namespace cose; 같은 표현이다.


단 이경우 strlen 이 이미 존재하기 때문에

strlen 과 cose::strlen 중 어느것을 호출하고 싶은건지 의도를 알 수 없다.

strlen 을 호출하기 위해서는 ::strlen 이라고 명시할 수 있고 ( 부모 폴더를 가리키는 셈 )

cose::strlen 을 호출하고 싶다면 어쩔 수 없이 풀네임을 불러줘야 한다.


똑같은 함수나 이름들이 가장 많이 사용되는 경우가 무엇일까?

바로 버전별로 코드를 유지해야 할 경우나, 비교가 필요한 테스트 / 최적화 등의 경우다.

namespace 를 활용해 버전관리를 편하게 해주기 위한 문법이 추가되었으니 관심 있으면 찾아보기 바란다.

( 뭐 딱히 편하진 않더라 )


구조체, 클래스, 공용체 들도 결국 폴더명을 지정하는 것과 같은 이름 형식을 갖는다.

그래서 어떻게 보면 namespace 가 특별한 기능없는 구조체들 처럼 보일수도 있다.

하지만 구조체 따위와 달리, 언제 어느때고 원하는 폴더에 코드를 밀어 넣을 수 있다는 것이 장점.


namespace A

{

    ...

};


namesapce B

{

    ...

};


namespace A

{

    ...

};


위와 같이 표현될 수 있다는 것이다.


이게 왜 장점이냐고?

가끔 무거운 헤더파일을 다른 헤더파일에 집어 넣는게 낭비처럼 여겨질 때가 있다.

어차피 구체적인 정의는 뒷단에서 이루어지고 namespace 가 정의된 객체의

포인터 정도 갖고 있으면 되는 경우,

포인터 타입이야 32비트에서 4바이트 64비트에서 8바이트 고정이 아닌가?

실제 내부가 사용될 때 말곤 그냥 4바이트나 8바이트 자료형으로 접근하면 되는데

내부를 꼭 알아야 할 필요는 없잖아?

그럴때 헤더파일을 포함시키지 않고 다음 처럼 쓸 수 있다.


namespace some_path

{

}; // 빈 껍데기만 선언 ( 컴파일러한테 걍 이런게 있어~ 자세히 알려고 하지마 라고 말해주는 거임 )


class ...

{

    some_path::some_class*           hehe;

    ...

};


프로젝트가 커지면 컴파일 속도를 최적화 하기 위해 여러가지 테크닉이 필요하다.

컴파일 시간이 몇 분 걸리면 당연히 개발 소요시간이 늘어나고 테스트 비용이 증가한다.

그런 이유에서도 아무곳에서나 동일한 이름으로 추가 선언될 수 있는 namespace 의 문법이 유용하다고 한 것이지~


다음 시간엔 template 과 class 의 문법에 대해 구체적으로 알아보겠다.