Data+

11. 클래스 템플릿의 이해2

by Qerogram

* 템플릿 Param 디폴트 값 사용.

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
template <typename T, int Size=100>
class Stack {
public:
  Stack() { Clear(); } 
  void Clear() { m_Count = 0; }
  int Count() const { return m_Count; }
  bool IsEmpty() const { return 0 == m_Count ? true : false; }
  int GetStackSize() const { return Size; }
  bool push( T data ) {
    if( m_Count >= Size ) return false;
    m_aData[ m_Count++ ] = data;
    return true
 }
 T pop() {
  if( m_Count < 1 ) return 0;
  --m_Count;
  return m_aData[ m_Count ];
 }
 private:
  T m_aData[Size];
  int m_Count;
};
 
#include <iostream>
 
using namespace std;
 
int main() {
  Stack<int64> kStack1;
  cout << "kStack1의 크기는 " << kStack1.GetStackSize() << endl;
  Stack<double> kStack2;
  cout << "kStack2의 크기는" << kStack2.GetStackSize() << endl;
  return 0;
}
 
cs

* 결과

kStack1의 크기는 64
kStack2의 크기는100


* 생성자를 이용한 스택크기 설정.

- 생성자에 explicit 키워드를 붙이면 암시적인 형 변환이 불가능하다.

-> 만약 Stack kStack1 = 64;로 선언을 해버리면 컴파일 에러가 발생한다.

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
template <typename T, int Size=100>
class Stack {
public:
  explicit Stack(int size) { 
    m_Size = size;
    m_aData = new T[m_Size];
    Clear();
  } 
  
  ~Stack() { delete[] m_aData; }
  
  void Clear() { m_Count = 0; }
  int Count() const { return m_Count; }
  bool IsEmpty() const { return 0 == m_Count ? true : false; }
  int GetStackSize() const { return m_Size; }
  bool push( T data ) {
    if( m_Count >= Size ) return false;
    m_aData[ m_Count++ ] = data;
    return true
 }
 T pop() {
  if( m_Count < 1 ) return 0;
  --m_Count;
  return m_aData[ m_Count ];
 }
 private:
  T* m_aData;
  int m_Count;
  int m_Size;
};
 
#include <iostream>
 
using namespace std;
 
int main() {
  Stack<int> kStack1(64);
  cout << "kStack1의 크기는 " << kStack1.GetStackSize() << endl;
  return 0;
}
 
cs

* 결과

kStack1의 크기는 64


* 클래스 템플릿 전문화

- 같이 게임을 했던 유저의 아이디를 저장해서 보여주고 싶은데, 기존 스택 클래스는 기본 자료형을 사용하는 걸 전제로했는데 문자열이라 표기가 안된다. 이런경우 전문화를 사용한다.

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
93
94
95
96
97
#include <string.h>
#include <iostream>
 
const int MAX_ID_LENGTH = 21;
void strncpy_s(char *dest,size_t sizeconst char *source, size_t n) {
    size_t i;
    for(i = 0; i < n; i++*(dest+i) = *(source+i);
}
 
template<typename T> class Stack {
  public :
    explicit Stack(int size) {
      m_Size = size;
      m_aData = new T[m_Size];
      Clear();
    }
    ~Stack() { delete[] m_aData; }
    void Clear() { m_Count = 0; }
    int Count() const { return m_Count; }
    bool IsEmpty() const { return 0 == m_Count ? true : false; }
    int GetStackSize() const { return m_Size; }
    bool push(T data) {
      if(m_Count >= m_Size) return false;
      m_aData[m_Count++= data;
      return true;
    }
    T pop() {
      if(m_Count < 1return 0;
      --m_Count;
      return m_aData[m_Count];
    }
    private :
      T* m_aData;
      int m_Count;
      int m_Size;
};
 
template<> class Stack<char*> {
  public :
    explicit Stack(int size) {
      m_Size = size;
      m_ppData = new char*[m_Size];
      for(int i = 0; i < m_Size; ++i) m_ppData[i] = new char[MAX_ID_LENGTH];
      Clear();
    }
    ~Stack() {
      for(int i =0; i < m_Size; ++i) delete[] m_ppData[i];
      delete[] m_ppData;
    }
    void Clear() { m_Count = 0; }
    int Count() const { return m_Count; }
    bool IsEmpty() const { return 0 == m_Count ? true : false; }
    int GetStackSize() const { return m_Size; }
    bool push(char* pID) {
      if(m_Count >= m_Size) return false;
      strncpy_s(m_ppData[m_Count], MAX_ID_LENGTH, pID, MAX_ID_LENGTH - 1);
      m_ppData[m_Count][MAX_ID_LENGTH-1= '\0';
      ++m_Count;
      return true;
    }
    char* pop() {
      if(m_Count < 1return 0;
      --m_Count;
      return m_ppData[m_Count];
    }
  private :
    char** m_ppData;
    int m_Count;
    int m_Size;
};
 
using namespace std;
 
int main() {
  Stack<int> kStack1(64);
  cout << "스택의 크기는 : " <<kStack1.GetStackSize() << endl;
  kStack1.push(10);
  kStack1.push(11);
  kStack1.push(12);
  
  int Count1 = kStack1.Count();
  for(int i = 0; i< Count1; ++i) cout << "유저 레벨 변화 => " << kStack1.pop() << endl;
  
  cout << endl;
 
  char GameID1[MAX_ID_LENGTH] ="NiceChoi";
  char GameID2[MAX_ID_LENGTH] = "SuperMan";
  char GameID3[MAX_ID_LENGTH] = "Attom";
  
  Stack<char*> kStack2(64);
  kStack2.push(GameID1);
  kStack2.push(GameID2);
  kStack2.push(GameID3);
  int Count2 = kStack2.Count();
  for(int i = 0; i < Count2; ++i) cout << "같이 게임을 한 유저의 ID =>" << kStack2.pop() << endl;
  return 0;
}
cs

* 결과

스택의 크기는 : 64
유저 레벨 변화 => 12
유저 레벨 변화 => 11
유저 레벨 변화 => 10

같이 게임을 한 유저의 ID =>Attom
같이 게임을 한 유저의 ID =>SuperMan
같이 게임을 한 유저의 ID =>NiceChoi


* 클래스 템플릿 부분 전문화

- 클래스 템플릿은 일부를 포인터나, 참조 혹은 구체적인 type 사용으로 부분 전문화가 가능하다.

* 구체적 type 사용에 의한 부분 전문화 문법 (아래의 코드를 보면 정확하다)

- template<typename T1, typename T2> class Test {...};

=> template <typename T1> class Test {...};


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
#include <iostream>
 
using namespace std;
 
template <typename T1, typename T2>
class Test{
  public :
  T1 Add(T1 a, T2 b) {
    cout << "일반 템플릿을 사용!" << endl;
    return a;
  }
};
 
template <typename T1> 
class Test<T1, float>{
  public :
  T1 Add(T1 a, float b)  {
    cout << "부분 전문화 템플릿 사용!" << endl;
    return a;
  }
};
 
int main() {
  Test<intint> test1;
  test1.Add(23);
  Test<intfloat> test2;
  test2.Add(23.0f);
  return 0;
}
cs


* 결과

일반 템플릿을 사용!
부분 전문화 템플릿 사용!

* 참고 - Thinking About C++ STL Programming

'코딩 > C&C++' 카테고리의 다른 글

13. STL list1  (0) 2017.04.15
12. 클래스 템플릿의 이해3  (0) 2017.04.15
10. 클래스 템플릿의 이해1  (0) 2017.04.14
9. 함수 템플릿의 이해2  (0) 2017.04.13
8. 함수 템플릿의 이해1  (0) 2017.04.13

블로그의 정보

Data+

Qerogram

활동하기