항목 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 객체는 일반화된 함수 포인터처럼 동작한다. (이 객체는 주어진 대상 시그너처와 호환되는 모든 함수호출성 개체를 지원한다고 한다. 이 융통성이 오히려 독이 되지 않을까낭~)



posted by 농사를 짓는 게임 프로그래머 최익필

댓글을 달아 주세요