템플릿(Template)
함수나 클래스를 개별적으로 다시 작성하지 않아도, 여러 자료 형으로 사용할 수 있도록 하게 만들어 놓은 틀이다.
템플릿을 사용하면 타입마다 별도의 함수나 클래스를 만들지 않고, 여러 타입에서 동작할 수 있는 단 하나의 함수나 클래스를 작성하는 것이 가능하다.
C#의 제네릭과 비슷하다고 생각하면 된다.
- 함수 템플릿(Function Template)
- 클래스 템플릿(Class Template)
이렇게 두 개로 나뉜다.
함수 템플릿(Function Template)
함수의 일반화된 선언을 의미한다. 함수 템플릿을 사용하면 같은 알고리즘을 기반으로 하면서, 서로 다른 타입에서 동작하는 함수를 한 번에 정의할 수 있다.
임의의 타입으로 작성된 함수에 특정 타입을 매개변수로 전달하면, C++ 컴파일러는 해당 타입에 맞는 함수를 생성해 준다.
문법
1
2
3
4
5
6
7
|
template <typename 타입이름>
함수의 원형
{
// 함수의 본체
}
|
cs |
예제 - 함수 템플릿
[기존 코드]
1
2
3
4
5
6
7
8
9
|
int sum(int a, int b)
{
return a + b;
}
float sum(float a, float b)
{
return a + b;
}
|
cs |
⬇️ ⬇️ ⬇️ ⬇️ ⬇️⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️
[Template 함수를 이용하여 수정한 코드]
1
2
3
4
5
|
template <typename T>
T sum(T a, T b)
{
return a + b;
}
|
cs |
클래스 템플릿(Class Template)
클래스의 일반화된 선언을 의미한다. 앞서 살펴본 함수 템플릿과 동작은 같으며, 그 대상이 함수가 아닌 클래스라는 점만 다르다. 클래스 템플릿을 사용하면, 타입에 따라 다르게 동작하는 클래스 집합을 만들 수 있다. 즉, 클래스 템플릿에 전달되는 템플릿 인수(template argument)에 따라 별도의 클래스를 만들 수 있게 된다. 이러한 템플릿 인수는 타입이거나 명시된 타입의 상숫값일 수 있다.
- 클래스 내부의 멤버 변수의 타입에 대해서 template로 선언할 때 사용한다.
- ⚠️선언 시에 유의할 점 : 멤버 함수를 클래스 외부에서 선언할 때, 꼭 template 선언을 다시 해주어야 한다⚠️
- 클래스 템플릿은 객체를 생성할 때 타입을 정해준다.
문법
1
2
3
4
5
6
7
8
|
template <typename 타입이름>
class 클래스템플릿이름
{
// 클래스 멤버의 선언
}
|
cs |
함수 템플릿과 마찬가지로 템플릿 정의 내에서 typename 키워드 대신에 class 키워드를 사용할 수 있다. 위에서 정의된 타입 이름은 클래스의 선언에서 임의의 타입으로 사용할 수 있다.
예제 - 클래스 템플릿
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
|
#include <iostream>
using namespace std;
template <typename T>
class Data
{
private:
T data_;
public:
Data(T dt);
T get_data();
};
int main(void)
{
Data<string> str_data("C++ 수업");
Data<int> int_data(12);
cout << "str_data : " << str_data.get_data() << endl;
cout << "int_data : " << int_data.get_data() << endl;
return 0;
}
template <typename T>
Data<T>::Data(T dt)
{
data_ = dt;
}
template <typename T>
T Data<T>::get_data()
{
return data_;
}
|
cs |
위처럼 클래스 템플릿으로부터 객체를 생성할 때에는 꺾쇠괄호(<>) 안에 템플릿에 전달된 인수 타입을 명시해야 한다.
전달된 매개변수의 타입을 가지고 컴파일러가 해당 타입에 맞는 함수를 생성해 주는 함수 템플릿과는 달리, 클래스 템플릿은 사용자가 사용하고자 하는 타입을 명시적으로 제공해야 한다.
예제 - 템플릿(Template)
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
|
#include <iostream>
#include <string>
using namespace std;
template<typename T>
class Character
{
public:
void Set(T name)
{
this->name = name;
}
void Print()
{
cout << "name : " << name << endl;
}
virtual void PrintName() = 0;
protected:
T name;
};
class Player : public Character<int>
{
public:
void PrintName() override
{
cout << "Player : " << name << endl;
}
};
class Monster : public Character<string>
{
public:
void PrintName() override
{
cout << "Monster : " << name << endl;
}
};
int main()
{
Player player;
player.Set(100);
player.PrintName();
Monster monster;
monster.Set("Oak");
monster.PrintName();
return 0;
}
|
cs |
예제 - Template Stack
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
|
#include <stdio.h>
#include <memory.h>
#include <assert.h>
#define MAX_STACK_COUNT 20
template<typename T>
class Stack
{
public:
Stack()
{
memset(values, 0, sizeof(T) * MAX_STACK_COUNT); // 시작주소부터 한 칸에 대한 크기 * 스택의 최대갯수
}
void Push(T value)
{
assert(top + 1 < MAX_STACK_COUNT); // 검증
values[++top] = value;
}
T Pop()
{
assert(Empty() == false);
T val = values[top--];
return val;
}
T Front()
{
return values[top];
}
bool Empty()
{
return top < 0 ? true : false;
}
private:
int top = -1;
T values[MAX_STACK_COUNT];
};
int main()
{
Stack<int> stack;
stack.Push(10);
stack.Push(20);
stack.Push(30);
stack.Pop();
stack.Push(40);
stack.Push(50);
while (stack.Empty() == false)
printf("%d\n", stack.Pop());
return 0;
}
|
cs |
출처 및 참고: TCPschool, 강의 짱 잘하시는 울 유니티 선생님 수업
HyunZzang의 프로그래밍 공간 / 함께 공부해요!!
도움이 되셨다면 "좋아요❤️" 또는 "구독👍🏻" 부탁드립니다 :)