template이란?
일반 자료형을 여러 자루의 색연필에 비유하자면, template는 하나의 펜에 내장된 여러개의 색상을 의미한다.
즉, 하나의 template변수로 여러 자료형을 사용할 수 있는 것이다.
https://blockdmask.tistory.com/43
참고한 사이트
함수 템플릿
int sum(int a, int b){
return a + b;
}
double sum(double a, double b)
{
return a + b;
}
이렇게 여러개의 자료형을 출력하기 위해 만들어진 함수를
// template로 구현하기
template<typename T>
T sum(T a, T b)
{
return a + b;
}
이렇게 하나의 함수로 대체할 수 있다.
#include<iostream>
#include<string>
using namespace std;
template <typename T>
T sum(T a, T b){
return a + b;
}
출처: https://blockdmask.tistory.com/43 [개발자 지망생]
다음과 같은 코드에
int main()
{
int a = 1;
int b = 2;
double d1 = 2.2;
double d2 = 3.3;
string s1 = "Show me";
string s2 = "The Money";
cout << "int와 double 합 : " << sum <double>(a, d1) << endl;
cout << "int와 double 합 : " << sum <int>(a, d1) << endl;
// 호출 시 명확하게 자료형을 표시하기 위해 < > 안에 매개변수의 자료형을 써준다.
cout << "double과 double의 합 : " << sum<double>(d1, d2) << endl;
cout << "string과 string의 합 : " << sum<string>(s1, s2) << endl;
return 0;
}
이렇게 main문을 입혀봤다.
함수 호출 시 <> 안에 쓰인 자료형은 출력될 자료형이 되고, 매개변수에는 여러개의 자료형이 동시에 올 수 있다.
#include <iostream>
#include <string>
using namespace std;
template <class T1, class T2>
void printAll(T1 a, T2 b) {
cout << "T1 : " << a << endl;
cout << "T2 : " << b << endl;
};
int main(void) {
string s1 = "Dok2";
string s2 = "On my way.";
int num1 = 27;
int num2 = 35;
double d1 = 3.14;
double d2 = 36.5;
cout << "[string, string]" << endl;
printAll(s1, s2); //printAll<string, string>(s1,s2);
cout << "[string, int]" << endl;
printAll(s1, num1); //printAll<string, int>(s1,num1);
cout << "[int, int]" << endl;
printAll(num1, num2);
cout << "[int, double]" << endl;
printAll(num1, d1);
cout << "[double, double]" << endl;
printAll(d1, d2);
cout << "[double, string]" << endl;
printAll(d1, s1);
return 0;
}
다음과 같이 template 변수가 두개인 경우에는 함수 이름 뒤에 <> 를 굳이 붙여주지 않는다.
각각 잘 출력된다.
근데 a + b와 연산자를 사용하면 오류가 뜬다. 서로 다른 인자를 특별한 처리를 수행하려면, 함수 템플릿의 특수화를 사용하면 된다
https://blockdmask.tistory.com/45
cout << "double과 double의 합 : " << sum(d1, d2) << endl;
다음과 같이 인자가 동일한 경우에는 굳이 <double>을 안써도 컴파일 되는데,
cout << "int와 double 합 : " << sum (a, d1) << endl;
이렇게 인자의 자료형이 다를때 <double>혹은 <int>를 안쓰면 에러
#include <iostream>
using namespace std;
// 함수 템플릿 예제
template <typename T> // 자료형(int, double ..) 자체가 함수의 매개변수가 됨
// 모든 자료형을 받을 수 있는 T 템플릿 변수를 설정해, 함수의
void printArray(const T* array, int count) {
for (int i = 0; i < count; i++) {
cout << array[i] << " ";
}
cout << endl;
}
int main()
{
const int ACOUNT = 5;
const int BCOUNT = 7;
const int CCOUNT = 6;
int a[ACOUNT] = { 1,2,3,4,5 };
double b[BCOUNT] = { 1.1, 2.2, 3.3, 4.4, 5.5, 6.6,7.7 };
char c[CCOUNT] = "Hello";
cout << "Array a contains : " << endl;
printArray(a, ACOUNT);
cout << "Array b contains : " << endl;
printArray(b, BCOUNT);
cout << "Array c contains : " << endl;
printArray(c, CCOUNT);
return 0;
}
강의노트 코드
의문점
1) 왜 포인터 자료형으로 매개변수를 받는 걸까?
2) 인자에 int형 변수를 넣으면 T라는 템플릿 변수가 int라는 value를 갖게 되는 것일까?
강의노트 코드2
#include <iostream>
using namespace std;
#include "stack.h"
int main() {
Stack <double> doubleStack(5); // element를 전부 double로 사용하겠다고 지정
double doubleValue = 1.1;
cout << "Pushing elements onto doubleStack\n";
while (doubleStack.push(doubleValue)) // 스택에 doubleValue 밑에부터 차례로 5개 넣음
{ // 스택의 element개수가 size보다 크게 되면 false가 반환되어 while 루프를 빠져나오게 된다
cout << doubleValue << " ";
doubleValue += 1.1; // 값을 1.1씩 증가시켜서 push하므로 1.1 / 2.2 / 3.3 / 4.4 / 5.5 의 형태가 스택에 존재하게 된다.
}
cout << "\n Stack is full, cannot push " << doubleValue << "\n\nPopping elements from double Stack " << endl;
// while문을 빠져나오는 경우는 스택이 가득 찬 경우밖에 없다.
while (doubleStack.pop(doubleValue))
cout << doubleValue << " ";
// isEmpty가 true일 때 pop함수에서 false를 반환하므로, 스택이 텅 비어있을 때 while문을 빠져나가게 된다.
cout << "\nSTack is empty, Cannot Pop\n";
Stack<int> intStack; // default size is 10
int intValue = 1;
cout << "\n\nPushing elements onto intStack\n";
while (intStack.push(intValue)) // 1이 제일 먼저 스택에 쌓인다.
{
cout << intValue << " ";
intValue++; // intValue가 차례로 증가하며 스택에 쌓임
}
cout << "\nStack is full, Cannot push " << intValue << "\n\nPopping elements from inStack\n";
while (intStack.pop(intValue))
cout << intValue << " ";
cout << "\nStack is empty, Caannot Pop" << endl;
return 0;
}
#include <iostream>
using namespace std;
#ifndef STACK_H
#define STACK_H
template <typename T> // Stack 클래스의 template 변수를 생성(T)
class Stack {
public:
Stack(int i = 10); // 기본 생성자
~Stack() {
delete[] stackPtr;
}
bool push(const T&);
bool pop(T&);
bool isEmpty() const {
return top == -1; // top 멤버 변수가 -1와 일치하면 Empty
}
bool isFull() const {
return top == (size - 1) ; // size를 10으로 지정(0~9)
}
private:
int size;
int top;
T* stackPtr; // T 포인터 자료형 변수(들어가는
};
#endif
template <typename T>
Stack<T> ::Stack(int s) // T 리턴값을 가지는 Stack 클래스 내의 멤버 함수 (여기서는 생성자)
:size(s > 0 ? s : 10), top(-1), stackPtr(new T[size]) {
}
template<typename T> // T 자료형의 템플릿변수 설정
bool Stack<T> ::push(const T& pushValue)
{
if (!isFull())
{
stackPtr[++top] = pushValue;
return true;
}
return false;
}
template<typename T>
bool Stack<T>::pop(T& popValue)
{
if (!isEmpty()) // 스택이 비어있지 않다면 -> 가득 차있다면
{
popValue = stackPtr[top--]; // popValue변수를 스택의 최상위에서 한단계 밑으로 지정
return true;
}
return false;
}
#include <iostream>
using namespace std;
template <typename T>
T Add(T num1, T num2)
{
cout << "T Add (T num1, T num2) " << endl;
return num1 + num2;
}
int Add(int num1, int num2)
{
cout << "Add(int num1, int num2)" << endl;
return num1 + num2;
}
double Add(double num1, double num2)
{
cout << "Add(double num1, double num2) " << endl;
return num1 + num2;
}
T에 int, T에 double을 넣었을 때 함수는 다음과 같이 만들어진다.
#include <iostream>
using namespace std;
template <typename T1, typename T2> // 여러가지 자료형에 대해서도 선언 가능
void ShowData(double num)
{
cout << (T1)num << ", " << (T2)num << endl;
} // double 형 num 인자를 T1, T2로 형변환하여 출력
int main()
{
ShowData <char, int>(65);
ShowData <char, int>(67);
ShowData <char, double>(68.9);
ShowData <short, double>(69.2);
ShowData <short, double>(70.4);
return 0;
}
이렇게 여러가지 자료형으로 연속으로 출력할 수 있따.
#include <iostream>
using namespace std;
class Point
{
private:
int xpos, ypos;
public:
Point(int x = 0, int y = 0)
:xpos(x), ypos(y) {}
void ShowPosition() const {
cout << "[" << xpos << "," << ypos << "]" << endl;
}
};
//template <typename T> // T 타입의 템플릿 변수
//void SwapData(T xpos, T ypos) {
// int temp = xpos;
// xpos = ypos;
// ypos = temp;
//}
//해답
template <typename T>
void SwapData(T& data1, T& data2)
{
T temp = data1;
data1 = data2;
data2 = temp;
}
#include <string>
int main()
{
Point pos1(10, 20);
Point pos2(1, 2);
SwapData(pos1, pos2);
pos1.ShowPosition();
pos2.ShowPosition();
return 0;
}
왜 주소값을 불러와서 쓰는걸까?
#include <iostream>
using namespace std;
template <typename T>
T SumArray(T arr[], int len)
{
T sum = (T)0;
for (int i = 0; i < len; i++)
{
sum += arr[i];
}
return sum;
}
int main()
{
int arr1[] = { 1,2,3 };
cout << SumArray(arr1, (sizeof(arr1) / sizeof(int))) << endl;
return 0;
}
이렇게 sum 값을 구하는 것을 구현할 때 배열의 길이 값을 구한 다음에 SumArray의 인자로 넣어 계산한다.
Stack(int s = 10)
:size(s > 0 ? : 10), top(-1), stackPtr(new T[size])
{ }
이렇게 Stack의 생성자에서(매개변수는 size에 대한 인자만 받는다. 기본값도 설정해주기) 는 size의 유효성 검증, top에 -1을 대입해주고, stackPtr 포인터 변수는 멤버 이니셜라이저에서 바로 new연산자를 사용해주어 메모리 할당(이때 입력받은 size값만큼 할당하고, 자료형은 T로 설정)
https://dydtjr1128.github.io/cpp/2020/01/08/Cpp-const.html
const 관련 글 참고
#include <iostream>
using namespace std;
template <typename T>
class Stack
{
private:
int top; // 현재 스택의 최상위 요소의 위치
T* stackPtr;
int size; // 스택의 사이즈
public:
Stack(int s = 10);
bool isEmpty()
{
return top == -1;
}
bool isFull() {
return top == (size - 1); // size가 만약에 10이면, top이 9일 때 스택이 꽉 찬 거니까 size - 1한 값이랑 top이랑 같을 때 Full이라고 인식
} // true 반환 시 Full하다는 것
bool Push(const T& pushValue);
bool Pop(T& popValue);
~Stack() {
delete[]stackPtr; // new 연산자로 할당받은 stackPtr T 자료형 포인터 변수 stackPtr의 메모리를 해제해준다.
}
};
template <typename T> //클래스 템플릿
Stack<T>::Stack(int s)
: size(s > 0 ? s : 0), top(-1), stackPtr(new T[size])
{}
template <typename T>
bool Stack<T>::Pop(T &popValue)
{
if (!isEmpty())
{
popValue = stackPtr[top--];
return true;
}
return false;
}
template <typename T>
bool Stack<T>::Push(const T& pushValue)
{ // T 자료형에 대한 const
if (!isFull())
{
stackPtr[++top] = pushValue;
return true;
}
return false;
}
/*
class Point {
public:
int x;
int ReturnValue();
};
int Point::ReturnValue() {
return x;
}*/
int main()
{
Stack<int> intStack; // T = int 인 Stack클래스 객체 intStack을 만들어준다. (생성자 호출)
int intValue = 1;
cout << "Pushing" << endl;
while (intStack.Push(intValue)) {
cout << intValue << " "; // push하는 값을 출력해준다.
intValue += 1; // 1씩 더하면서 스택에 값을 대입해준다.
}
cout << endl;
cout << "Stack is Fulll. Start Popping" << endl;
while (intStack.Pop(intValue)) {
cout << intValue << " ";
} // pop
cout << endl << "Stack is Empty " << endl;
return 0;
}
아무튼 이렇게 하면 된다잉
#include <iostream>
#include <string>
using namespace std;
#include "stack.h"
template <typename T>
void testStack(Stack<T>& theStack, T value, T increment, const string& stackName) {
cout << "Pushing elements onto " << stackName << endl;
while (theStacl.push(value))
{
cout << value << " ";
value += increment;
}
cout << endl << "Stack is full. Cannot push " << value << endl
<< endl
<< "Poping elements from " << stackName << endl;
while (theStack.pop(value))
{
cout << value << " ";
}
cout << endl << "Stack is empty. Cannot pop" << endl
<< endl;
}
int main()
{
Stack <double> doubleStack(5); // size = 5이고 T = double인 Stack 생성
Stack< int>intStack; // default size = 10이고 T= int인 intStack생성
testStack(doubleStack, 1.1, 1.1, "doubleStack");
// 스택 객체, value = 1.1, increment = 1.1, stackName을 인자로 받는다.
testStack(intStack, 1, 1, "intStack");
return 0;
}
똑같은 기능을 하는 testStack함수를 만들었따.
하나의 템플릿 변수를 설정하여 처리할 수 있었다.
'Major Study > Object Oriented Programming' 카테고리의 다른 글
연산자 오버로딩 / 상속 / 다형성 구현 프로젝트 해결 과정 (0) | 2021.10.08 |
---|---|
객체지향 프로그래밍2 상속, 연산자 오버로딩, 다형성, 템플릿 관련 의문점 정리 및 해결 (2) | 2021.06.15 |
객체지향 프로그래밍2 기말고사 대비 문제 wirte-up (0) | 2021.06.14 |
객체지향 프로그래밍 프로젝트 (상속과 다형성, 가상함수) 해결 과정 / 가상 함수, 다형성 개념 정리 (0) | 2021.05.31 |
2021 객체지향 프로그래밍 중간고사 대비 (0) | 2021.04.17 |