상속(inheritance)
여러 자료를 보면 상속을 'A is a B'의 관계로 설명하곤 한다.
전에 객체 생성은 크게 세 단계를 거친다고 언급한 적이 있다.
그런데 이런 의문이 생길지도 모른다. 자식 클래스의 멤버 이니셜라이저에 부모 클래스의 생성자를 넣어두었으니깐 당연히 부모 클래스의 생성자가 호출되는 것이 아니냐고. 직접 클래스를 만들어서 해보면 확인할 수 있을 것이다. 멤버 이니셜라이저에서 부모 클래스가 호출되지 않아도 자식 클래스의 객체를 생성하기 위해서는 부모 클래스의 생성자가 먼저 반드시 호출된다는 사실을 알 수 있다.
그림을 보면 자전거가 부모 클래스이고, 산악 자전거, 도로 자전거, 세 번째는 무슨 자전거지? 찾아보기 귀찮으므로 땡땡 자전거. 여튼 산악, 도로, 땡땡 자전거들은 자전거로부터 파생된 것들이다. 그래서 "산악 자전거는 자전거의 하나이다.", "도로 자전거는 자전거의 일종이다.", 즉 'A is a B' 관계가 성립한다. 상속을 간략하고 투박하게 설명하면 이런 것이다. 상속에 대핸 자료는 많고, 쉽게 접할 수 있느니깐 그만 하도록 하고 넘어가자.
우리가 상속 자체보다는 상속받은 클래스(자식 클래스)의 객체는 부모 클래스의 객체와 무엇이 다른지에 주목하고자 한다.
자식 클래스의 생성 과정
먼저 상속을 설명하면서 처음부터 끝까지 사용할 코드를 살펴보자. 그림이 자전거이니 자전거로 클래스를 만들었다.
생성자, 소멸자에 대해 이해하고 있다면 간단한 코드이다. 전과 달라진 점은 MTBicycle 클래스가 Bicycle 클래스를 상속받고 있다는 점 뿐이다. Bicycle 클래스는 생성자에서 자신의 이름과 속력을 초기화한다. MTBicycle 클래스의 생성자를 살펴보면 멤버 이니셜라이저 부분에서 자신의 부모 클래스인 Bicycle 클래스의 생성자를 호출하고 있다.전에 객체 생성은 크게 세 단계를 거친다고 언급한 적이 있다.
- 객체를 위한 메모리 공간 할당
- 멤버 이니셜라이저를 통한 초기화
- 생성자 몸체 부분 실행
MTBicycle 클래스의 생성 과정을 위의 세 단계를 적용해서 살펴보자. 객체를 위한 메모리 공간이 할당된다. 그 다음 생성자의 멤버 이니셜라이저를 먼저 살펴본다. 그런데 멤버 이니셜라이저에서 부모클래스의 생성자가 선언되어 있다. 이것을 먼저 실행해줘야 한다. 그래서 부모 클래스의 생성자가 자신의 생성자보다 먼저 호출되게 된다. 이는 매우 중요한 사실이므로 잘 이해하도록 하자. 부모 클래스의 생성자를 보니 멤버 이니셜라이저가 또 존재한다. speed을 초기화하라는 내용이다. 간단히 speed를 초기화해주고 나면 생성자 몸통에서 name을 위한 공간을 동적 할당하고 초기화해준다. 부모 클래스의 생성자 호출이 완료되면 비로소 자신의 생성자를 호출하여 전체 객체 생성 과정을 완료하게 된다.
부모 클래스로부터 상속받은 클래스의 객체를 생성하는 경우, 자신의 생성자만 호출한다고 생각하기 쉽다. 자식 클래스의 객체를 생성하기 위해서는 반드시 부모 클래스의 생성자가 호출됨을 잊으면 안된다.
설명한 내용을 바탕으로 main() 함수를 실행시켜 보자.
내용은 간단하다. 자식 클래스인 MTBicycle의 객체를 하나 생성한다. 생성자와 소멸자에 각각 자신의 생성자가 호출되었다는 것을 출력하는 코드를 넣어두었다. 결과가 어떻게 나올지 예상해보자. 앞에서 언급한 내용에 따르면 자식 클래스의 객체를 생성하기 위해서는 먼저 부모 클래스의 생성자가 호출된다. 그럼 MTBicyle 클래스의 객체가 생성자가 호출되기 전에 Bicycle 클래스의 생성자가 호출된다.그런데 이런 의문이 생길지도 모른다. 자식 클래스의 멤버 이니셜라이저에 부모 클래스의 생성자를 넣어두었으니깐 당연히 부모 클래스의 생성자가 호출되는 것이 아니냐고. 직접 클래스를 만들어서 해보면 확인할 수 있을 것이다. 멤버 이니셜라이저에서 부모 클래스가 호출되지 않아도 자식 클래스의 객체를 생성하기 위해서는 부모 클래스의 생성자가 먼저 반드시 호출된다는 사실을 알 수 있다.
자식 클래스의 소멸 과정
위 코드를 실행해본 사람이라면 소멸 과정이 생성 과정이 다르다는 점을 이미 확인했을 것이다. 위의 두 클래스는 꼼꼼하게도 소멸자에서 new 연산자로 동적 할당한 메모리를 반환하고 있다. 그러면 생성 과정과 어떻게 다른지 알아보자. 결론부터 말하면 소멸 순서는 생성 순서와 반대이다. 생성 과정은 부모에서 자식 순서로 진행되지만, 소멸 과정은 자식에서 부모 순서로 진행된다. 이 순서로 소멸자를 호출하면서 소멸자에 내부에 코드가 있다면 그 코드를 실행시킨다. 위의 두 클래스는 모두 소멸자에서 자신이 생성자에서 동적 할당한 메모리를 스스로 반환하도록 만들어져있다. 객체 소멸 과정에서 메모리 누수가 발생하지 않도록 하기 위함이다.
정리하면
- 자식 클래스의 객체를 생성 과정은 부모로부터 자식 순서로 생성자를 호출한다.
- 자식 클래스의 객체를 생성 과정은 자식으로부터 부모 순서로 소멸자를 호출한다.
댓글 없음:
댓글 쓰기