# 클래스 템플릿

## 클래스 템플릿 <a href="#ed-81-b4-eb-9e-98-ec-8a-a4-ed-85-9c-ed-94-8c-eb-a6-bf" id="ed-81-b4-eb-9e-98-ec-8a-a4-ed-85-9c-ed-94-8c-eb-a6-bf"></a>

함수 템플릿과 마찬가지로 클래스도 템플릿으로 정의가 가능하다.

## Stack 클래스 <a href="#stack-ed-81-b4-eb-9e-98-ec-8a-a4" id="stack-ed-81-b4-eb-9e-98-ec-8a-a4"></a>

스택은 LIFO(Last in first out) 구조로 되어 있는 자료구조 이다.

| 속성       | 설명                     |
| -------- | ---------------------- |
| T\* buf  | 템플릿 자료형 데이터를 저장할 공간    |
| int top  | 현재 데이터의 위치를 기억         |
| int size | 스택에 보관할 수 있는 데이터의 최대개수 |

| 메서드       | 설명          |
| --------- | ----------- |
| Stack()   | 생성자         |
| \~Stack() | 소멸자         |
| push()    | 데이터 하나를 저장  |
| pop()     | 데이터 하나를 꺼내옴 |

`Stack.h`

```
#ifndef __STACK_H__
#define __STACK_H__

template <typename T>
class Stack {
  T* buf;
  int top;
  int size;
public:
  Stack(int size);
  virtual ~Stack();
  void push(T a);
  T pop();
};

#endif
```

`Stack.cpp`

```
#include "Stack.h"
#include <iostream>
using namespace std;

template<typename T>
Stack<T>::Stack(int size)
  : top(0), size(size)
{
  buf = new T[size];
}

template<typename T>
Stack<T>::~Stack() {
  delete[] buf;
}

template<typename T>
void Stack<T>::push(T a) {
  if (top >= size) {
    cout << "Error : Stack full" << endl;
    return;
  }
  buf[top++] = a;
}

template<typename T>
T Stack<T>::pop() {
  if (top <= 0) {
    cout << "Error : Stack empty" << endl;
    return NULL;
  }
  return buf[--top];
}
```

`main.cpp`

```
#include <iostream>
using namespace std;
#include "Stack.h"

int main() {
  Stack<int> iStack(3);
  iStack.push(1);
  iStack.push(2);
  iStack.push(3);
  iStack.push(4);

  cout << iStack.pop() << endl;
  cout << iStack.pop() << endl;
  cout << iStack.pop() << endl;
  cout << iStack.pop() << endl;

  Stack<double> dStack(3);
  dStack.push(1.5);
  dStack.push(2.5);
  cout << dStack.pop() << endl;
  dStack.push(3.5);
  cout << dStack.pop() << endl;
  cout << dStack.pop() << endl;
  return 0;
}
```

### 템플릿 클래스의 파일 구분 <a href="#ed-85-9c-ed-94-8c-eb-a6-bf-ed-81-b4-eb-9e-98-ec-8a-a4-ec-9d-98-ed-8c-8c-ec-9d-bc-ea-b5-ac-eb-b6-84" id="ed-85-9c-ed-94-8c-eb-a6-bf-ed-81-b4-eb-9e-98-ec-8a-a4-ec-9d-98-ed-8c-8c-ec-9d-bc-ea-b5-ac-eb-b6-84"></a>

예제를 실행하면 링킹과정에서 오류가 발생한다.

템플릿 클래스는 **일반적으로 하나의 헤더파일에 모든 멤버함수의 정의**를 모두 작성한다.

그것이 싫다면 **main.cpp**에 다음과 같이 `include`문을 추가 한다.

```
(...)
#include "Stack.cpp"
(...)
```

## Linked list 템플릿 <a href="#linked-list-ed-85-9c-ed-94-8c-eb-a6-bf" id="linked-list-ed-85-9c-ed-94-8c-eb-a6-bf"></a>

연결리스트는 노드들의 포인터로 연속적으로 연결되어 순차적으로 접근 할 수 있는 자료구조 이다.

### Node 템플릿 클래스 <a href="#node-ed-85-9c-ed-94-8c-eb-a6-bf-ed-81-b4-eb-9e-98-ec-8a-a4" id="node-ed-85-9c-ed-94-8c-eb-a6-bf-ed-81-b4-eb-9e-98-ec-8a-a4"></a>

Node 클래스는 데이터를 저장하고 다음 노드에 대한 정보를 가지고 있다. `Node.h`

```
#ifndef __NODE__
#define __NODE__

template<typename D>
class Node {
public:
  D data;
  Node* next;
  Node(): next(NULL) {}
};

#endif
```

### List 템플릿 클래스 <a href="#list-ed-85-9c-ed-94-8c-eb-a6-bf-ed-81-b4-eb-9e-98-ec-8a-a4" id="list-ed-85-9c-ed-94-8c-eb-a6-bf-ed-81-b4-eb-9e-98-ec-8a-a4"></a>

List 클래스는 더미노드 기반의 단순연결리스트를 구현하였다.

| 속성              | 설명            |
| --------------- | ------------- |
| Node\<T>\* head | 더미노드          |
| Node\<T>\* cur  | 현재 가리키는 노드 위치 |
| Node\<T>\* cur  | 이전 노드 위치      |
| int count       | Node의 개수      |

| 메서드        | 설명                  |
| ---------- | ------------------- |
| List()     | 생성자                 |
| \~List()   | 소멸자                 |
| insert()   | 연결리스트의 앞에 Node를 삽입  |
| first()    | 연결리스트의 첫번째 Node로 이동 |
| next()     | 다음 Node로 이동         |
| remove()   | Node 제거             |
| getCount() | Node의 개수 반환         |

```
#ifndef __LIST__
#define __LIST__

#include "Node.h"

template <typename T>
class List {
  Node<T>* head;
  Node<T>* cur;
  Node<T>* before;
  int count;
public :
  List();
  ~List();
  void insert(T data);
  bool first(T& data);
  bool next(T& data);
  T remove();
  int getCount();
};

/* 생성자
 * 더미 노드를 생성
 */
template <typename T>
List<T>::List() 
  : cur(NULL), before(NULL), count(0)
{
  head = new Node<T>; // 더미노드 생성
  head->next = NULL; 
}

/* 소멸자 
* head->next 가 NULL일때까지 삭제 
*/
template <typename T>
List<T>::~List() {
  Node<T>* temp = head; // 더미노드 부터 
  while (temp) {
    head = temp->next; // temp의 다음 노드를 head로 
    delete temp; // 삭제
    temp = head; // 다음삭제할 노드를 temp로 
  }
}

/* insert()
* 값을 받아서 Node를 하나 생성
*/
template <typename T>
void List<T>::insert(T data) {
  Node<T>* newNode = new Node<T>; // 새로운 노드를 할당
  newNode->data = data; // 값을 저장

  newNode->next = head->next; // 첫번째 노드를 새노드의 다음노드로 지정
  head->next = newNode; // 첫번째 노드로 지정
  count++; // 개수를 증가
}

/* first()
* 현재 위치를 맨 처음 Node로 이동시킨다.
* 매개변수에 data값을 참조 시킨다.
* 데이터가 없으면 false 반환
*/
template <typename T>
bool List<T>::first(T& data) {
  if (head->next == NULL) { // 데이터가 없다면 
    return false; // false 반환
  }
  before = head; // 이전포인터는 헤더
  cur = head->next; // 현재 포인터는 더미노드의 next로 첫번째 노드
  data = cur->data; // 현재 데이터를 참조한다.
  return true;
}

/* next()
* 현재 위치를 다음 Node로 이동시킨다.
* 매개변수에 data값을 참조 시킨다.
* 데이터가 없으면 false 반환
*/
template <typename T>
bool List<T>::next(T& data) {
  if (cur->next == NULL) { // 다음 데이터가 없다면
    return false; // false 반환
  }

  before = cur; // 이전 위치를 현재위치로 이동
  cur = cur->next; // 현재위치를 다음위치로 이동
  data = cur->data; // 데이터 값을 참조
  return true;
}

/*
* 현재 위치의 Node를 삭제하고 데이터를 반환한다.
*/
template <typename T>
T List<T>::remove() {
  T data = cur->data; // 현재 데이터 복사
  before->next = cur->next; // 이전 위치의 다음을 현재의 다음으로 
  delete cur; // 현재 Node 삭제
  count--; // 개수 1 감소
  cur = before; // 현재 위치를 이전위치로 이동
  return data;
}

/* getCount()
* 현재 데이터의 개수 반환
*/
template <typename T>
inline int List<T>::getCount() {
  return count;
}
#endif
```

`main.cpp`

```
#include <iostream>
using namespace std;
#include "List.h"

int main() {
  List<int> list;
  int data;
  list.insert(10);
  list.insert(20);
  list.insert(23);
  list.insert(25);
  list.insert(30);
  list.insert(34);

  cout << "현재 데이터의 개수 : " << list.getCount() << endl;
  if (list.first(data)) {
    cout << data << endl;
    while (list.next(data)) {
      cout << data << endl;
    }
  }
  cout <<endl << "20이상 30이하 삭제" << endl << endl;
  if (list.first(data)) {
    if (data >= 20 && data <= 30) {
      list.remove();
    }
    while (list.next(data)) {
      if (data >= 20 && data <= 30) {
        list.remove();
      }
    }
  }

  cout << "현재 데이터의 개수 : " << list.getCount() << endl;
  if (list.first(data)) {
    cout << data << endl;
    while (list.next(data)) {
      cout << data << endl;
    }
  }
  return 0;
}
```

### 사용자 정의 객체를 저장하는 리스트 <a href="#ec-82-ac-ec-9a-a9-ec-9e-90-ec-a0-95-ec-9d-98-ea-b0-9d-ec-b2-b4-eb-a5-bc-ec-a0-80-ec-9e-a5-ed-95-98-e" id="ec-82-ac-ec-9a-a9-ec-9e-90-ec-a0-95-ec-9d-98-ea-b0-9d-ec-b2-b4-eb-a5-bc-ec-a0-80-ec-9e-a5-ed-95-98-e"></a>

이전에 만들었었던 String 클래스를 연결리스트에 사용해 보자.

[String Class 바로가기](https://ezcode.gitbook.io/bnb-cpp/operator-overloading/string-class)

`main.cpp`

```
#include <iostream>
using namespace std;
#include "List.h"
#include "String.h"

int main() {
  List<String> list;
  String data;
  list.insert("안녕하세요");
  list.insert("반값습니다.");
  list.insert("안녕하세요");
  list.insert("반가워요");

  cout << "현재 데이터의 개수 : " << list.getCount() << endl;
  if (list.first(data)) {
    cout << data << endl;
    while (list.next(data)) {
      cout << data << endl;
    }
  }
  
  cout <<endl << "안녕하세요 삭제" << endl << endl;
  if (list.first(data)) {
    if (data == "안녕하세요") {
      list.remove();
    }
    while (list.next(data)) {
      if (data == "안녕하세요") {
        list.remove();
      }
    }
  }

  cout << "현재 데이터의 개수 : " << list.getCount() << endl;
  if (list.first(data)) {
    cout << data << endl;
    while (list.next(data)) {
      cout << data << endl;
    }
  }
  
  return 0;
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ezcode.gitbook.io/bnb-cpp/template/class-template.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
