안녕하세요 삽잡이입니다.
지난 시간에는 클래스간의 관계에 대하여 알아봤었습니다.
오늘은 그중에서 일반화 관계 즉, 상속과 다형성에 대해서 알아보려고 합니다.
일반화...란 뭐라고 했었나요? 'is a' 관계라고 했죠...
예를 들어볼까요?
'삽잡이는 사람이다.' '삽잡이는 남자다.' 등등...
삽잡이는 사람에 기반하고 있으며, 삽잡이는 남자에 기반하고 있습니다.
또한, 남자는 사람에 기반하고 있죠...
흠... 모두 사람에 기반하고 있네요...
그렇다는 뜻은,
사람이라는 기반 클래스를 통해서
남자, 삽잡이와 같은 파생 클래스를 통해 파생을 표현할 수 있다 이겁니다...
어렵게 설명했나요? 그러면 실제 코드를 보시며 이해를 해보도록 하겠습니다.
1 2 3 4 5 6 7 8 9 10 11 | class Musician { string name; public: Musician(string name); ~Musician(void); void Play(); void Greeting(); protected: string GetName()const; }; | cs |
1 2 3 4 | Musician::Musician(string name) { this->name = name; } | cs |
자... 이제 파생 클래스인 Pianist를 보겠습니다.
1 2 3 4 5 6 7 8 | class Pianist : public Musician { public: Pianist(string name); ~Pianist(void); void Tuning(); }; | cs |
콜론 연산자 (:) 를 사용하고 기반 클래스명을 쓰면,
이는 Musician이라는 클래스를 상속받고 있다고 설명할 수 있습니다.
자... Pianist라는 클래스에는 '튜닝하다'의 기능을 가지고 있네요...
실제 main 함수에서 이 클래스를 사용해본다면 말입니다...
1 2 3 4 | Pianist *pianist = new Pianist("삽잡이"); pianist->Greeting(); pianist->Play(); pianist->Tuning(); | cs |
자... 이와 같이 Pianist 클래스에 선언되어있는 Tunning 뿐만 아니라,
상속받은 기반클래스인 Musician 클래스 내의 기능들 또한 사용할 수 있다는 것이죠...
'피아니스트는 음악가이다'...
즉, 피아니스트는 음악가에서 파생됬다고 볼 수 있습니다.
뭐.. 일반화, 상속화, 파생... 다들 세부적으로는 차이가 있을지라도
다 같은 의미로 사용된다고 보시면 됩니다...
아무튼, 공통적인 부분을 기반형식에 일반화 시켜 정의하고,
그곳으로 부터 파생시켜 공통적이지 않은 부분들을 구현하는 것...
이 또한 객체 지향의 매력 아니겠습니까?
이를 응용한다면 Musician 이라는 클래스를 기반으로
기타리스트, 드러머 등등을 표현하는데도 무리가 없겠죠?
자.. 그런데 말입니다...
파생된 클래스는 기반 클래스의 기능들 또한 사용할 수 있는데 즉, 상속 받을 수 있는데요
어떻게 파생 개체가 생성되고 초기화되어지는 것일까요?
예를 하나 들어보겠습니다...
삽잡이가 태어나기 이전에 사람으로 태어나지 않습니까?
그러니까... 사람의 본질을 가지고 태어나 삽잡이라는 캐릭터가 입혀졌다...
이와 같이 말씀드릴 수 있는데요... 웩... 너무 예시를 끼어맞췄나...
이와 같이... 객체가 생성될 때에는 가장 본질인
즉, 기반이 되는 클래스가 가장 먼저 생성이 되고 그 뒤에 파생 클래스가 생성됩니다.
(소멸 될 때에는 반대로 진행됩니다...)
하하... 정리하여 말씀드리자면
파생형식이 만들어질 때에는 기반형식부터 만들어지고 파생형식이 만들어진다는 것입니다.
기반 형식에 매개변수를 받는 생성자가 있다고 생각해보신다면,
파생 형식 또한 매개변수를 받는 생성자가 있어야됩니다.
그렇지 않다면 컴파일 에러가 나죠...
왜냐 어떤 형식으로 만들어야될지 컴파일러는 판단을 하지 못하기 때문입니다...
아무튼...
파생된 클래스의 소스 코드에서 기반 클래스에 속한 멤버 필드는
해당 기반 클래스의 생성자를 호출하여 초기화시켜야합니다.
이때 사용하는 것이 이니셜라이저 입니다.
한번 보실까요?
1 2 3 4 | Pianist::Pianist(string name):Musician(name) { cout<<"피아니스트 "<<name<<" 생성"<<endl; } | cs |
자... Pianist의 string name은 곧 Musician의 클래스에 있는 name의 것과 같기 때문에
Musician 클래스의 생성자를 호출하여 초기화 해줘야합니다.
캡슐화할때 이니셜라이저를 사용하셨던 기억들이 있으실 터인데요,
이니셜라이저를 언제 사용하느냐에 대해서 정리를 해보자면
1. 상수 멤버 필드 초기화
2. 기본 생성자가 없는 기반 형식 생성하고자 할 때
이와 같이 크게 두가지로 정리될 수 있습니다. 아무튼... 다음으로 넘어가보도록 하겠습니다.
'그런데요, 파생된 클래스에서는 꼭 기반 클래스의 기능만을 사용해야하나요?'
아니요... 파생 클래스에서도 기반 클래스에 있는 동일한 이름의 기능을
자신의 스타일에 맞게 구현할 수 있습니다...
즉, 기반형식의 기능을 새롭게 정의할 수 있다 이겁니다.
기반형식의 정의 한 것은 없어지고 재정의한 기능이 수행되죠...
이를 '오버라이딩'이라고 합니다. 기반 형식의 정의한 이름과 같은 이름을
파생형식에서 재정의하는 것...
이렇게 되면 기존의 정의된 내용은 무효화 됩니다.
1 2 3 4 | void Student::Study() { cout<<name<<" 공부하다."<<endl; } | cs |
학생이라는 클래스가 공부하는 기능을 가지고 있었습니다.
이를 상속받은 날라리 클래스에서는 오버라이딩하여 새롭게 정의할 수 있게 되죠...
1 2 3 4 5 6 7 | void MStudent :: Study() { cout<<"으아 공부하기 싫어~"<<endl; // 기반형식의 기능 사용 가능. Student::Study(); } | cs |
이렇게 새롭게 정의할 수 있다 이겁니다.
아래 주석을 보시면 알겠지만 이와 같은 형태를 사용하면
이전의 즉, 기반형식의 기능 또한 사용할 수 있게 됩니다...
파생클래스에서 기반 클래스명 + 스코프 연산자(::) 를 붙여 메서드를 호출하면
무효화된 메서드를 사용할 수 있다 이거죠~!
아무튼 ... 저 MStudent는 미x의... M... 푸하하....
아무튼 츤데레네요... 공부하기 싫다더니 결국은 하는....
이번시간은 여기까지 하도록 하겠습니다!
이상 삽잡이였습니다!
'삽질의 현장 > - C++' 카테고리의 다른 글
#009_시(c)시(c)해서 C++?!_프로토 타이핑 ... (0) | 2015.07.09 |
---|---|
#008_시(c)시(c)해서 C++?!_이름은 같은데 하는짓은 다 달라... 다형성 (0) | 2015.07.08 |
#006_시(c)시(c)해서 C++?!_클래스간의 관계 (0) | 2015.07.06 |
#005_시(c)시(c)해서 C++?!... 조금은 불편한 생성자... (0) | 2015.07.02 |
#004_시(c)시(c)해서 C++?!... C와 C++의 변수와 동적할당 (0) | 2015.07.02 |