안녕하세요 삽잡이입니다.
오늘은 다형성에 대해서 배워보도록 하겠습니다...
겉으로는 보이는 건 하나지만, 구체적으로는 모두 다를 수 있다...
이게 바로 다형성입니다...
파생을 통해서 얻을 수 있는 이점중 하나는 바로
기반 클래스 형식의 포인터 변수로 파생된 개체를 관리할 수 있다는 것입니다...
말이 좀 어렵죠?
이말인 즉, 기반 클래스에 직접적으로나 간접적으로나 상속 되는 클래스는 모두 관리할 수 있다 이겁니다...
더 어렵나요? 허허...
이전 시간에 예시를 들었던....
피아니스트, 드러머, 기타리스트 등 음악가와 관련된 개체들을
음악가 형식의 포인터 변수로 관리 할 수 있다 이거죠...
좀더 생각해본다면,
음악가 형식의 변수 즉, 기반 클래스 형식의 포인터 변수 하나로
여러개의 파생 클래스 형식의 객체들을 관리 할 수 있다 이겁니다.
A는 B고 B는 C다... 고로 A는 C다... 이와 같은 논리정도?? 하하..
지난시간에 사용한 클래스들을 다시한번 재활용해보도록 하겠습니다...
까먹을 수도 있으니... 소환!
음악가 클래스와...
1 2 3 4 5 6 7 8 9 | class Musician { string name; public: Musician(string name); void Play(); protected: string GetName()const; }; | cs |
피아니스트 클래스 입니다...
1 2 3 4 5 6 7 8 | class Pianist : public Musician { public: Pianist(string name); void Tuning(); void Play(); }; | cs |
자... 이곳에는 똑같은 Play() 메서드가 있지만
지난시간에 피아니스트에 맞도록 오버라이드 했었습니다...
그렇다면... 어디 위의 논리가 통하는지 실제로 구현해보도록 ㅎ
1 2 3 4 | Musician *mu = new Pianist("삽잡이"); mu->Play(); delete mu; | cs |
직접 구현하여 확인해보신다면, Pianist의 기능이 아닌
Musician의 play() 기능이 나오는 것을 확인하실 수 있습니다....
음... 이럴 수는 없습니다...
이래서는 피아니스트, 첼리스트, 바이올리니스트 등등 아름다운 협주를 기대할 수 없게 됩니다...
모두 한 음만 내게 생겼어요...
여기서 C++에서의 특징 하나를 찾아낼 수 있습니다...
바로, 포인터의 자료형이 기준이라는 것이죠.... 객체의 자료형이 아니라
그 객체를 가리키는 포인터의 자료형이 기준이다.... 이겁니다...
즉!!! 포인터 자료형에 해당되는 클래스에만 접근이 가능하다 이거죠!!!
자 아무튼... 이제 다형성을 다시한번 불러봅시다~
도와줘요 다형성~!!
1 2 3 4 5 6 7 8 9 | class Musician { string name; public: Musician(string name); virtual void Play(); protected: string GetName()const; }; | cs |
짜잔~!
기존의 Musician 클래스와의 차이점... 확인 가능하십니까?
바로 Virtual 이라는 친구가 나왔습니다... 누구냐 넌...
이 친구가 바로 우리의 아름다운 합주를 도와줄...
호출하는 놈은 동일하지만 실제 기능은 각기 다르게 해주는
다형성의 중요한 특징을 가지고 있는 virtual, 즉 가상 메서드라고 합니다.
우선 정답부터 말씀드리자면,
파생 클래스에서 각기 다르게 사용할 메서드 같은 경우에는
기반 메서드에 있는 해당 메서드 맨 앞에 virtual을 붙여주면 됩니다...
그렇다면 virtual를 붙인 가상함수 Play()가 생겼습니다... 그렇다면 아까
1 2 3 4 | Musician *mu = new Pianist("삽잡이"); mu->Play(); delete mu; | cs |
이 코드는 Musician 클래스의 Play()가 아닌,
Pianist 클래스 안의 Play()의 기능이 동작하게 된다 이 말씀~!
virtual에 대해서 정리해보자면,
해당 키워드를 붙인 함수를 바로 가상 함수라고 부르며,
포인터 변수의 자료형이 기반이 되지 않고, 실제로 가리키는 객체를 참조하여
호출을 결정한다 이겁니다....
그렇다면 가상 함수의 매커니즘을 한번 살펴보도록 하죠...
모든 예시는 위의 클래스를 기준으로 설명하겠습니다...
우선 생성자는 어떤 순서대로 생성된다고 했었죠?
바로 기반 클래스 부터 시작해서 파생 클래스가 생성된다 했었습니다.
자... 그렇다면 우선 class 내에 있는 name과 같은 멤버 필드를 메모리 주소에 보관하게 되고요
virtual 함수가 하나라도 존재하는 개체가 생성될 경우에
4 byte 짜리 가상 메모리 주소를 보관할 수 있는 테이블이 동적으로 생성됩니다...
1 | Musician *mu = new Pianist("삽잡이"); | cs |
Musician 클래스의 생성자가 호출되어 메모리가 할당 된 뒤에
이제 Pianist 클래스의 생성자가 호출하게 됩니다.
그러면서 재정의에 의해서 Musician의 Play() 함수의 주소가 변경하는 작업을 수행하게 됩니다.
이렇게 virtual 함수 메커니즘도 알아봤습니다...
다시한번 가상 메소드에 대해서 정리해본다면 (중요하니까...)
참조하고 있는 변수 형식이 아닌 생성하고자 하는 객체의 형식에 맞도록 하기 위해
기반 형식의 함수 선언부에 virtual 키워드를 사용하라!
그리하면 실질적인 객체의 행위를 하게 된다!
이겁니다!
자... 이번에는 마지막으로 순수 가상 메소드에 대해서 알아보고자 합니다.
우선 살펴보고 설명에 들어가도록 하겠습니다...
1 2 3 4 5 6 7 8 9 | class Musician { string name; public: Musician(string name); virtual void Play()=0;//순수 가상 메서드(추상 메서드) protected: string GetName()const; }; | cs |
자....
기존 가상 함수에 0을 붙였네요.... 즉, 함수의 몸체를 정의하지 않은 것입니다.
다시 정리해서 말씀드리자면,
순수 가상 함수란, 함수의 몸체를 정의하지 않은... 파생 클래스에서 해당 기능을 만들라는
약속을 하는 함수라고 생각하시면 됩니다.
파생 클래스에서 오버라이딩을 해야하는 필요가 있으면서
굳이 Musician이라는 객체 생성을 할 필요가 없을 때,
순수 가상함수로 선언하여, 약속만 해둔다면 불필요한 객체 생성을 막을 수 있게 되죠...
자... 지금까지 다형성에 대해서 알아봤습니다....
정리하는 겸 주절주절 써대느라...
글이 참 더럽군요 ^^....
글쓰는거 좋아한다고 말하기에도 부끄러운 최근 글들....
여유로워진다면... 양질의 글을... 푸하하...
배우는 입장에서... 듣고 정리하고 포스팅한다는게 부끄럽지만
여간 정성을 쏟기 힘드네요 허허...
아무튼... 저의 푸념이었습니다...
이상 삽잡이었습니다!
'삽질의 현장 > - C++' 카테고리의 다른 글
#010_시(c)시(c)해서 C++?!_ 잡다구리한 것들... (싱글톤, 기능성, 다형성) (0) | 2015.07.10 |
---|---|
#009_시(c)시(c)해서 C++?!_프로토 타이핑 ... (0) | 2015.07.09 |
#007_시(c)시(c)해서 C++?!_상속을 가지고 놀아보자~ (0) | 2015.07.08 |
#006_시(c)시(c)해서 C++?!_클래스간의 관계 (0) | 2015.07.06 |
#005_시(c)시(c)해서 C++?!... 조금은 불편한 생성자... (0) | 2015.07.02 |