항목 34 에서 가상 함수의 단점을 지적한 부분이 책에는 있는데, 나 같은 경우 생략했다. ^^; 단점은 가상함수는 기본 정의도 제공되기 때문에, 제공된 기본정의를 사용하다보면, 정작 다른 작동을 해야 할 때도 재정의를 해야 한다는것을 까먹고, 기본정의를 사용하여 디버깅이 아주 힘들수 있다는 점이다. 이것을 애초에 막고자 하려면 가상 함수를 대채할 무엇인가가 필요하다는 주제로 쓰여진 항목 35 이다.
자~ 이러한 단점들이 있음에도 가상 함수를 사용 한다는것을 찜찜해 하는 영리한 사람들은 생각하기 시작했다.
"대체 할 수 있는게 없을까?"
필자는 두 팔을 다 걷어, 다른 방법을 몇가지 알려 준다고, 곽용재씨께서 말씀해 주셨다. ㅋ;
하나,
비가상 인터페이스 관용구(non-virtual interface : NVI)를 통한 템플릿 메서드 패턴,
이 방법은 Base 클래스가 public: non-virtual function안에 private: virtual function 를 호출하여, 파생 클래스의 virtual function 을 호출할 수 있도록 하는 개념이다. 당연히 파생 클래스에선 virtual function을 재정의 할 수 있다. 하지만 파생 클래스만에선 private: 영역 이기에 외부에서 접근을 할수 없다. 그래서 protected 이하로 상속해서 해결 할수도 있지만, 그렇게 되면 캡슐화가 의미가 없어지니 NVI 관용구를 도입한 의미가 없어진다.
하나,
함수 포인터로 구현한 전략 패턴
클래스 멤버 변수로 함수포인터를 두어, 멤버 함수가 이 함수포인터를 이용하여 특정 함수를 호출하는 방법으로, 최대의 장점은 같은 타입의 객체라도 다른 함수로 작동되게 할수 있고, .. 뭐 변수로 둔다는 점에서의 모든 장점을 취할 수 있다. 하지만 private: 영역을 접근 할수 없다는게 흠이다.
하나,
tr1::function 으로 구현한 전략 패턴
함수 포인터로 구현한 전략 패턴와 개념상 크게 다르지 않지만, 포인터 변수라기 보단 함수 포인터 변수를 가지는 tr1::function 객체이다. .. 자세한 내용은 tr1:function 을 알아야 하니, 모르겠다. (이 방법이 private 를 해결해 주지는 않는다)
하나,
"고전적인" 전략 패턴
아예 그 처리만 하는것을 다른 클래스로 빼고, has-a 관계로 상속해두고, 그 처리가 필요할때 그 처리하는 객체의 가상함수를 호출하는 식으로 바꾸는 패턴, 이것은 다른 쪽 계통에 속해 있는 가상 함수로 대체한다는 개념이다.
이것 말고도 많은 방법이 있으니, 너무 이것에 국한되서 생각하지는 말라고 한다. 뭐~ 이래서 어렵지... 필자는 가상 함수 대신 쓸 무엇인가에 대해서 필히 짚고 넘어가야 한다고 말하고 있다..
이것만은 잊지 말자!
1. 가상 함수 대신 쓸 수 있는 다른 방법을 생각해보자~
2. 객체에 필요한 기능을 외부 함수로 빼면 private: 를 접근 할수 없다, 그렇다고 public: 으로 쓸 것이라면 그냥 가상함수 쓰는게 낫다고 한다.
3. tr1::funtion 객체는 일반화된 함수 포인터처럼 동작한다. (이 객체는 주어진 대상 시그너처와 호환되는 모든 함수호출성 개체를 지원한다고 한다. 이 융통성이 오히려 독이 되지 않을까낭~)
자~ 이러한 단점들이 있음에도 가상 함수를 사용 한다는것을 찜찜해 하는 영리한 사람들은 생각하기 시작했다.
"대체 할 수 있는게 없을까?"
필자는 두 팔을 다 걷어, 다른 방법을 몇가지 알려 준다고, 곽용재씨께서 말씀해 주셨다. ㅋ;
하나,
비가상 인터페이스 관용구(non-virtual interface : NVI)를 통한 템플릿 메서드 패턴,
이 방법은 Base 클래스가 public: non-virtual function안에 private: virtual function 를 호출하여, 파생 클래스의 virtual function 을 호출할 수 있도록 하는 개념이다. 당연히 파생 클래스에선 virtual function을 재정의 할 수 있다. 하지만 파생 클래스만에선 private: 영역 이기에 외부에서 접근을 할수 없다. 그래서 protected 이하로 상속해서 해결 할수도 있지만, 그렇게 되면 캡슐화가 의미가 없어지니 NVI 관용구를 도입한 의미가 없어진다.
하나,
함수 포인터로 구현한 전략 패턴
클래스 멤버 변수로 함수포인터를 두어, 멤버 함수가 이 함수포인터를 이용하여 특정 함수를 호출하는 방법으로, 최대의 장점은 같은 타입의 객체라도 다른 함수로 작동되게 할수 있고, .. 뭐 변수로 둔다는 점에서의 모든 장점을 취할 수 있다. 하지만 private: 영역을 접근 할수 없다는게 흠이다.
하나,
tr1::function 으로 구현한 전략 패턴
함수 포인터로 구현한 전략 패턴와 개념상 크게 다르지 않지만, 포인터 변수라기 보단 함수 포인터 변수를 가지는 tr1::function 객체이다. .. 자세한 내용은 tr1:function 을 알아야 하니, 모르겠다. (이 방법이 private 를 해결해 주지는 않는다)
하나,
"고전적인" 전략 패턴
아예 그 처리만 하는것을 다른 클래스로 빼고, has-a 관계로 상속해두고, 그 처리가 필요할때 그 처리하는 객체의 가상함수를 호출하는 식으로 바꾸는 패턴, 이것은 다른 쪽 계통에 속해 있는 가상 함수로 대체한다는 개념이다.
이것 말고도 많은 방법이 있으니, 너무 이것에 국한되서 생각하지는 말라고 한다. 뭐~ 이래서 어렵지... 필자는 가상 함수 대신 쓸 무엇인가에 대해서 필히 짚고 넘어가야 한다고 말하고 있다..
이것만은 잊지 말자!
1. 가상 함수 대신 쓸 수 있는 다른 방법을 생각해보자~
2. 객체에 필요한 기능을 외부 함수로 빼면 private: 를 접근 할수 없다, 그렇다고 public: 으로 쓸 것이라면 그냥 가상함수 쓰는게 낫다고 한다.
3. tr1::funtion 객체는 일반화된 함수 포인터처럼 동작한다. (이 객체는 주어진 대상 시그너처와 호환되는 모든 함수호출성 개체를 지원한다고 한다. 이 융통성이 오히려 독이 되지 않을까낭~)
'책 정리 > Effective C++ 3판' 카테고리의 다른 글
항목 40: 다중 상속은 심사숙고해서 사용하자. (0) | 2008.07.25 |
---|---|
항목 39 : private 상속은 심사숙고해서 구사하자 (0) | 2008.07.19 |
항목 38: "has-a(...는...를가짐)" 혹은 "is-implemented-in-terms-of(...는...를 써서 구현됨)"를 모형화 할 때는 객체 합성을 사용하자. (2) | 2008.07.18 |
항목 37: 어떤 함수에 대해서도 상속받은 기본 매개변수 값은 절대로 재정의 하지 말자. (0) | 2008.07.16 |
항목 36 : 상속받는 비가상 함수를 파생 클래스에서 재정의 하는 것은 절대 금물! (1) | 2008.07.14 |
항목 34: 인터페이스 상속과 구현 상속의 차이를 제대로 파악하고 구별하자. (0) | 2008.07.09 |
항목 33: 상속된 이름을 숨기는 일은 피하자 (4) | 2008.07.02 |
항목 32: public 상속 모형은 반드시 "is-a(...는 ...의 일종이다)"를 따르도록 만들자. (0) | 2008.07.02 |
항목 31: 파일 사이의 컴파일 의존성을 최대로 줄이자 (0) | 2008.07.02 |
항목 30: 인라인 함수는 미주알고주알 따져서 이해해 두자 (0) | 2008.07.01 |
최근댓글