티스토리 뷰
가상 함수 대신 쓸 것들도 생각해 두는 자세를 시시때때로 길러 두자.
1) 비가상 인터페이스 관용구(non-virtual interface)를 사용하자.
- 공개되지 않은 가상 함수를 비가상 public 멤버 함수로 감싸서 호출하는, 템플릿 메서드 패턴의 한 형태
- NVI에서 가상 함수가 엄격하게 public 일 필요는 없다.
- 장점 : 가상 함수가 호출되기 전에 어떤 상태를 구성하고 가상 함수가 호출된 후에 그 상태를 없애는 작업을 래퍼를
통해 공간적으로 보장된다.
*비가상 인터페이스 관용구(non-virtual interface)란?
- 사용자로 하여금 public 비가상 멤버 함수를 통해 private 가상 함수를 간접적으로 호출하게 만드는 방법.
- 관용구에 쓰이는 비가상 함수는 가상함수의 래퍼라고 부른다.
2) 가상함수를 함수 포인터 데이터 멤버로 대체하자.
- 군더더기 없이 전략 패턴의 핵심만을 보여주는 형태.
- 장점 : 다양한 상황에 대처할 수 있는 유연한 클래스를 만들 수 있다.
- 프로그램 실행 도중 함수를 바꿀 수 있다.
- 단점 : private 로 선언된 변수의 경우 함수가 클래스 내부가 아닌 외부에 있기 때문에 변수에 접근할 수 없는 상황이 벌어진다.
3) 가상함수를 tr1::function 데이터 멤버로 대체하여, 호환되는 시그너처를 가진 함수 호출 성 개체를 사용할 수 있도록 만들자
- 전략 패턴의 한 형태.
- 장점 : 함수 포인터 보다 유연한 클래스를 만들 수 있다.(멋진 코드)
4) 한쪽 클래스 계통에 속해 있는 가상 함수를 다른 쪽 계통에 속해 있는 가상 함수로 대체하자.
- 전략 패턴의 전통적인 형태
- 장점 : 표준적인 전략 패턴 구현 방법에 친숙할 경우 빨리 이해할 수 있다.
예제
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
class GameCharacter
{
public:
virtual int healthValue() const;
};
EX1) NVI 관용구를 통한 템플릿 메서드 패턴
class GameCharacter
{
public:
int healthValue() const;
{
int retVal = doHealthValue();
return retVal;
}
private:
virtual int doHealthValue() const
{
}
};
// healthValue(비가상함수)를 doHealthValue(가상함수)의 랩퍼(wrapper)라고 부름
Ex2) 함수 포인터로 구현
class GameCharacter; //전방선언
int defaultHealthCalc(const GameCharacter& gc); //이곳에서 계산합니다.
class GameCharacter
{
public:
typedef int (*HealthCalcFunc)(const GameCharacter&);
explicit GameCharacater(HealthCalcFunc hcf = defaultHealthCalc):healthFunc(hcf){}
//생성자.
int healthValue() const
{
return healthFunc(*this);
}
private:
HealthCalcFunc healthFunc;
};
Ex3) tr1::function 구현
class Game Character; //전방선언
int defaultHealthCalc(const GameCharacter& gc); //이곳에서 계산합니다.
class GameCharacter
{
public:
typedef std::trl::function<int (const GameCharacter& ) > HealthCalcFunc;
explicit GameCharacater(HealthCalcFunc hcf = defaultHealthCalc):healthFunc(hcf){}
//생성자.
int healthValue() const
{
return healthFunc(*this);
}
private:
HealthCalcFunc healthFunc;
};
Ex4) 고전적인 전략(Strategy) 패턴
class GameCharacter;
class HealthCalcFunc
{
public:
virtual int calc(const GameCharacter& gc) const
{
}
};
HealthCalcFunc defaultHealthCalc;
class GameCharacter
{
public:
explicit GameCharacter(HealthCalcFunc *phcf = &defaultHealthCalc)
: pHealthCalc(phcf)
{
}
int healthValue() const
{
return pHealthCalc->calc(*this);
}
private:
HealthCalcFunc *pHealthCalc;
};
|
cs |
결론
가상 함수 대신에 쓸 수 있는 다른 방법으로 NVI 관용구 및 전략 패턴을 들 수 있다.
이 중 NVI 관용구는 그 자체가 템플릿 메서드 패턴의 한 예이다.
객체에 필요한 기능을 멤버 함수로부터 클래스 외부의 비멤버 함수로 옮기면, 그 비멤버 함수는 그 클래스의 public 멤버가 아닌 것들을 접근할 수 없다는 단점이 생긴다.
tr1::function 객체는 일반화된 함수 포인터처럼 동작한다.
이 객체는 주어진 대상 시그너처와 호환되는 모든 함수 호출 성 개체를 지원한다.
- Total
- Today
- Yesterday
- C++
- 스쿠버 다이빙
- C#
- 울릉도
- 서귀포
- 제주도
- C#.NET
- 스쿠버다이빙
- Build
- 블루버블다이빙팀
- CMake
- 현포다이브
- Effective c++
- DLL
- 블루버블
- 블루버블다이브팀
- 패턴
- OpenSource
- 네트워크 정보
- Linux
- Windows
- C# 고급 기술
- C
- 서귀포블루버블
- 외돌개
- 암호화
- 성산블루버블
- PowerShell
- effective
- script
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |