C++Builder Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
C++빌더 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
메신저 프로젝트
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C++빌더 강좌/문서
C++Builder Programming Tutorial&Docments
[96] 클래스의 상속과 합성이 있을 때, 인스턴스 생성시 실행 순서.
김태선 [jsdkts] 17600 읽음    2006-05-19 23:57
클래스를 상속하고 나서 클래스의 인스턴스를 생성할때
어떤 순서로 구체적으로 실행되는지 잘 아는 것은 중요합니다.
클래스를 하나 상속하고 또 하나는 클래스내에 합성하여 어떤 순서로 코드가 진행되는지 보겠습니다.

예제.
//---------------------------------------------------------------------------
class TB
{
public:
    int  k;
    TB(int seed)
        : k(seed)
    {
        k++;
    }
};

class TA : public TB    // 상속
{
public:
    TB    b; // 합성
    TA(int  k)
        : b(k),
        TB(k)
    {
        b.k++;
    }
};
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
    TA  a(2);
    Caption = a.b.k;
}
//---------------------------------------------------------------------------



위 소스를 설명하기 쉽게 스크릿샷으로 첨부했으며, 줄번호를 가지고 설명하겠습니다.
물론 소스를 긁어다 한줄씩 추적해보면 쉽게 알수 있습니다.
과연 여러분들이 위에 폼이 생성될때의 OnCreate 이벤트에 TA a(2); 라고 코딩된 것이
생각한대로의 순서대로 실행되는지 잘 살펴보시기 바랍니다.
이것은 C++의 기초에 해당하지만 의외로 정확한 순서를 모르는 사람이 있는 듯 합니다.

26번줄의 TA a(2); 에 브레이크포인트를 걸고 실행하면서 한줄씩 추적해보면
실행순서는 아래와 같습니다.
한스텝씩 실행순서를 보이고 그에 대한 설명을 합니다.
TA클래스에서는 TB 클래스를 상속받았는데, TA클래스 내부에 TB b; 라고 TB클래스를 합성한 부분도 보입니다.
이는 상속한 경우과 합성한 경우의 실행 우선순위를 살펴보기 위해 일부러 상속과 합성을 동시에 표시했습니다.

라인번호와 코드 그리고 다음줄에 설명을 달았습니다.
//---------------------------------------------------------------------------
26. TA a(2);
    브레이크포인트를 걸어서 추적을 시작하는 라인이죠.
16. TA(int  k)
    당연히 TA 생성자 라인이 실행되어야 겠지요
    하지만 여기서 잊지 말아야 하는 것은, 클래스의 생성자는 상위 클래스(모클래스)의 생성자가 먼저 실행되고
    하위 클래스(자손 클래스)의 생성자가 뒤에 실행되는게 원칙이라는 사실입니다.
    그러므로 당연히 TA 생성자가 실행되는게 아니라 TA의 모클래스인 TB의 생성자가 먼저 실행되어야 합니다.
    즉 TA 생성자 라인으로 가야하는 것이 아니라 TB 의 생성자 라인으로 먼저 가야 하죠.
    하지만 컴파일러는 TB의 생성자의 프로토타입을 가르키고 있습니다.
    왜 일까요?
    그것은 2가지 이유때문입니다. 첫째는 모클래스가 먼저 생성되어야 하지만, 생성시 인자를 건네주는 것은
    자손클래스이므로,  자손클래스를 먼저 가르켜야 합니다.
    그래야 자손클래스를 통해 인자가 넘어가는 과정이 성립됩니다.
    두번째는 자손클래스에 합성된 클래스에 대한 초기화를 생성자의 함수 본체가 실행되기 이전에
    먼저 해주기 위해서입니다. 물론 이건 모클래스 생성이후에 동작이 일어닙니다.
18.   TB(k)
    TA(int k) : b(k), TB(k) 라고 된 생성자 프로토타입라인에서 가장 먼저 실행되는 것은
    TB(k) 입니다. 이는 모클래스이기 때문에 모클래스 생성자 우선 실행의 원칙때문입니다.
    그래서  18라인의 TB(k)가 실행됩니다.
5. TB(int seed = 100)   
    그러니 자연 TB의 생성자 프로토타입으로 순서가 옮겨오게 됩니다.
6. : k(seed)
    TB는 모클래스가 없는 클래스이므로 k = seed; 의 생성자 프로토타입식 표현인 k(seed)가 실행됩니다.
    모클래스도 없는 상황에서 생성자 함수 본체가 실행되기 전에 미리 이런식으로 초기화 할 필요도 없는데
    이런 식으로 코딩을 하는 것은 별로 좋은 습관이 아니죠. 특히 그 변수가 클래스가 아닐때는
    썩 바람직하지 않습니다. C++에서 생성자(인자) : 클래스(초기값) 식의 문법을 두는 것은 클래스내에
    합성한 클래스에 대한 초기화를 위해서 둔 것이지  예제에 보인바와 같이 일반 변수 초기화하라고 준비한
    문법이 아닙니다. 그럼에도 불구하고 실무에서 이런 코드를 보는 일이 빈번하는 것은 약간 잘못된 코딩 습관
    이라고 할수 있습니다. 예제는 실행순서를 알기 위해 예제로 그렇게 표시한 것 뿐이니 오해 마시기를..
    C++의 클래스는 15번라인 같이 클래스를 합성할때 생성자의 인수를 직접 표기할 수 없습니다.
    5번 라인이 TB(int seed = 100) 같이 생성자를 생략할 수 있는 형태가 아닌, TB(int seed) 와 같이 되어
    있다면, 생성인자를 반드시 주어야만 하는데, 15번 라인을 TB b(5); 식으로 선언할 수 없다는 것이죠.

    왜 클래스내의 멤버변수(클래스)를 선언할때는 초기값이나 클래스의 생성자 값을 줄수 없을까요?
    클래스 내에서는 int  nVar = 100; String  sVar = "초기값입니다"; 또는 int  nVar(100);
    String  sVar("초기값입니다"); 식으로 생성자 값을 줄수 없는 근본이유는, 클래스는 생성될때
    멤버변수의 데이타 영역을 스택 또는 힙에 확보한 뒤 그 번지를 되돌려야 하는데, 이렇게 생성자 값을
    지정할 수 있게 허용하면 초기화된 멤버변수의 값은 미리 정적데이타 영역에 생성하고,
    나머지는 스택 또는 힙에 생성해서 관리해야 하는 이중 구조를 가져야 하는데 이는 단일한 메모리
    번지를 생성의 결과물로 되돌려야 하는 구조에서는 실현하기 곤란하기 때문입니다.
    컴파일러가 억지로 구현하자면 안되는 것은 아니나, 부자연스러운 동작을 해야 하기 때문입니다.

    그러므로 생성자를 반드시 요구하는 클래스에 대해서는 인수를 주어 생성할 필요가 있는데 이를 위해
    "상술한 생성자(인자) : 모클래스_생성자(인자), 클래스내에_합성된_클래스(초기값) " 과 같은
    문법이 존재하는 것입니다. 17번 라인같이 합성한 클래스에 대해서 그리고 18번 라인같이
    모클래스에 대해서는 이런식의 표기법이 아니면 그 생성자에 대한 처리를 할수가 없기 때문입니다.
8. k++;
    이제 비로소 TB의 생성자 함수 본체 코드가 실행됩니다.
17. : b(k),
    모클래스 생성자의 본체가 실행된 후는 합성한 클래스에 대한 생성자를 실행할 차례입니다.
    그래서 이 라인이 실행되는 것이죠.
5. TB(int seed = 100)
    당연히 합성한 클래스에 대한 생성자라인으로 이동해 와야 겠죠.
6. : k(seed)
    먼저 초기화할 것을 실행합니다.
8. k++;
    함수 본체가 실행되죠.
20. b.k++;
    이제 TB의 생성자 실행이 끝났으므로, TA의 생성자의 본체가 실행되어야 겠죠.
    이 생성자 본체 코드가 실행됨으로써 함수 생성의 과정은 종료됩니다.
27. Caption = a.b.k;
    26번 라인의 실행이 끝나고 27번 라인으로 진행했네요.


정확하게 순서를 알지 않아도 몇번 헤딩하면 실무에 큰 지장이 없으나,
그래도 정확하게 아는게 좋음은 두 말할 필요가 없습니다.

+ -

관련 글 리스트
96 클래스의 상속과 합성이 있을 때, 인스턴스 생성시 실행 순서. 김태선 17600 2006/05/19
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.