살군의 보조기억 장치

Another memory device…

선언, 정의, 초기화, 기본생성자 그리고 시그너처

with one comment

약간 햇갈리는 부분이 있어 정리를 했다.

선언declaration은 코드에 사용되는 ‘어떤 대상’의 이름과 타입을 컴파일러에게 알려 주는 것입니다. 하지만 구체적인 세부사항은 선언에 들어 있지 않습니다. 예를 들어, 다음과 같은 것들이 선언입니다.

extern int X;                      // 객체 선언
std::size_t numDigits(int number); // 함수 선언
class Widget;                      // 클래스 선언
template class GraphNode;          // 템플릿 선언

정의definition는 선언에서 빠진 구체적인 세부사항을 컴파일러에게 제공하는 것입니다 객체의 경우에 있어서 정의는 컴파일러가 그 객체에 대한 메모리를 마련해 놓는 부분이 됩니다. 함수나 함수 템플릿에 대한 정의는 그들에 대한 코드 본문body을 제공하는 것이고요 클래스 혹은 클래스 템플릿의 경우에는 그 클래스 혹은 템플릿의 멤버를 넣어 준 결과가 정의입니다.

int x;                                           // 객체 정의

std::size_t numDigits(int number)                // 함수 정의
{                                                // (이 함수의 반환 값은
    std::size_t digitsSoFar = 1;                 // 매개변수에 들어 있는
                                                 // 숫자의 개수입니다.
    while ((number /= 10) != 0) ++digitsSoFar; 
    return digitsSoFar;
}

class Widget {                                   // 클래스 정의
public:
    Widget();
    ~Widget();
    ...
};

template<typename T> class GraphNode {           // 템플릿 정의
public:
    GraphNode();
    ~GraphNode();
    ...
};

초기화initialization는 어떤 객체에 최초의 값을 부여하는 과정입니다. 사용자 정의 타입으로 생성한 객체의 경우, 초기화는 생성자에 의해 이루어집니다.

기본 생성자default constructor는 어떤 인자도 주어지지 않은 채로 호출될 수 있는 생성자입니다. 원래부터 매개변수가 없거나 모든 매개변수가 기본 값을 갖고 있으면 기본 생성자가 될 수 있습니다.

class A {
public:
    A();                                     // 기본 생성자
};

class B {
public:
    explicit B(int x = 0, bool b = true);    // 기본 생성자: "explicit"의 의미는
};                                           // 좀더 아래에서 확인할 수 있습니다.

class C {
public:
    explicit C(int x);                       // 기본 생성자가 아닙니다.
};

클래스 B와 C의 생성자가 explicit로 선언되어 있는 것이 보일 것입니다. 이렇게 선언된 생성자는암시적인타입변환을수행하는데쓰이지않게됩니다. 뭐,물론타입변환이명 시적으로 되는 곳에는 쓰일 수 있지만요

void doSomething(B bObject);    // B 타입의 객체를 하나 받는 함수

B bObj1;                        // B 타입의 객체 

doSomthing(bObj1);              // 문제없습니다. B 객체를 doSomething에 넘깁니다.

B bObj2(28);                    // 좋습니다. int 인자 28로부터 B를 하나 만듭니다.
                                // (bool 인자는 기본 값인 true가 자동으로 들어갑니다)

doSomething(28);                // 에러입니다! doSomething은 B를 취해야 합니다.
                                // 그냥 int가 들어가면 안됩니다. 게다가
                                // int에서 B로 바뀌는 암시적 변환이 없습니다.

doSomething(B(28))              // 좋습니다. 지금의 호출에서는
                                // B 클래스의 생성자를 써서 int에서 B로
                                // 명시적으로 변화(즉, 캐스팅)합니다(캐스팅에
                                // 대한 이야기는 항목 27에서 확인하세요).

explicit로 선언된 생성자는 explicit가 아닌 것들과 비교할 때 꽤 쓸모가 많습니다. 프로그래머가 예상하지도 못했던(대개 바라지 않던) 타입 변환을 막아 주기 때문입니다 필자의 경우, 암시적 타입 변환에 생성자가 사용될 여지를 남겨둘 뚜렷한 이유가 없는 한, 생성자는 explicit 선언을 우선적으로 합니다. 여러분도 주저 마시고 이런 식으로 해 보시기 를 적극 추천하는 바입니다.

모든 함수의 선언문에는 시그너처signature, 다시 말해 그 함수의 매개변수 리스트와 반환 타입이 나와 있습니다. 함수의 경우엔 시그너처가 그 함수의 타입입니다. 앞에서 보신 numDigits 함수의 시그너처는 std::size_t(int) 입니다. 말하자면 ‘int 하나를 취하고 std::size_t를 반환하는 함수’라는 의미인 것이죠. ‘시그너처’에 대한 공식적인 C++ 정의에서는 함수의 반환 타입을 제외하고 있지만, 이 책에서는 반환 타입도 시그너처의 일부로 간주합니다. 이쪽이 여러모로 더 쓸모가 있거든요

참고
Advertisements

Written by gomiski

2014/02/05 at 4:07 am

Posted in General, Lecture

One Response

Subscribe to comments with RSS.

  1. […] 여기에서 한 번 언급했던 내용인 함수 시그너처signature 가운데 매개변수parameter가 생략 혹은 주석처리된 경우를 본 적이 있는가? 물론 컴파일이 된다. 되니까 이야기를 시작한 것이지. 단, c++에서만. c에서는 컴파일이 안된다. […]


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: