보통 초보들이 제법 구조를 갖춘 소스코드들을 보면서 당황하게 되는 것이,
난생 처음 보는 장황한 이름들에 당혹감을 느끼기 때문일듯 하다.
어디까지가 이름인지 어디까지가 연산인지도 구별하기 힘들지도.
그래서 까막눈을 트이게 해 주기 위해 먼저 코드 읽는 법을 설명해 주려 한다.
그러기 위해선 "왜? 이렇게 표기해야 하는가" 또한 설명되어야 겠지.
함수의 다형성 ( 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 의 문법에 대해 구체적으로 알아보겠다.
아저씨 저좀도와주세욤
추천~
폴리모피즘의 객체지향에서의 의미는 조금 다른 것 같은데. 객체지향 개념에서는 어떤 명령에 대해서 A B C D 객체 중 뭘 시행할지를, 밖에서 결정하는게 아니라 모A B C D 모두한테 보내서 해당되는 놈만 실행되도록 하는걸 다형성이라고 하던데 - return 0;
왱~ 뭣땜에 찡찡거려 피에로양~
앙 가상함수의 경우엔 runtime 에 결정되니깐~ 그건 별도로 설명하는게 옳을 것 같음유~
이건 큰 붓~ 그건 작은 붓~ 합쳐서 완성~
루비인데 코드가돌아가지않습니다
ㅋㅋㅋㅋ 니가 좀 찾아봐~ 나도 루비로 문자열 함수 몇 개 만들어 본게 전부임유~
가상함수 말고 개념 말하는겁니다잉 모든 객체지향 언어들에 다 적용되는 '개념' - return 0;
어젠되던게 오늘고쳐서 안되니 슬프네요
응. 근데 C++ 설명이잖아. 사실 C++ 은 객체지향 이라기 민망한 언어고.
흑흑 - return 0;
니가 말한 개념에 가장 근접한게 그나마 가상함수 개념이라 그렇게 이야기 한거지~ small talk 계열처럼 메시지 주고 받는 언어들이나 상수까지 모조리 객체화 되어 있는 언어들이랑 엮어 설명하면 애들한테 가뜩이나 난해한 C++ 을 어케 설명함 ㅋㅋ
나중에 component 모델을 C++ 로 구현하면 조금 비스무리 해지긴 하는데~ 그때까진 초보강좌니깐~
이거 얼마나 어디까지 연재하나요
그.. 글쎄요. 갤에 초보가 없어질때 까지나 내가 무진장 귀찮아질때 까지?
갤에 초보가 없어질리는 없으니 귀챃지 않아지시길 바라는수밖에...
초보는 언제나 있다
-> 코세영감의 강좌는 계속된다(결론0
저장 - dc App