일 반 화 일 반 화 일 반 화 일 반 화 ((((템 플 릿 템 플 릿 템 플 릿 템 플 릿 )))) 프로그램의 로직을 효율적으로 바꿔보자 .
이 장에서 다룰 내용 일반 함수 (함수 템플릿 ) 1 일반 클래스 (클래스 템플릿 ) 2
01_ 일반 함수 (함수 템플릿 ) 일반화란 (템플릿이란 ) 구조가 동일한 경우에 대해 아래 그림처럼 내용물을 바꾸기만 하면 같은 모양으로 만들어지는 틀을 만드는 작업
01_ 일반 함수 일반 함수 다양한 자료형에 대해서 적용되는 일반적인 연산들의 집합 일반 함수는 te m p la te 라는 키워드를 이용하여 생성 일반 함수를 정의하는 방법은 다음과 같다 . te m p la te < ty p e n a m e T > 반환값 함수명 (입력인자 ) te m p la te < ty p e n a m e T > 반환값 함수명 (입력인자 ) { 문장 .. . } T 에는 일반 함수에 의해 사용되는 자료형의 이름이 들어간다 .
[기본예제 13 - 1] 일반 함수의 사용 # 1
01#include<iostream> 02usingnamespace std; 03template <typename T> T generic_abs(T a) 04{ 05T ret; 06ret = a<0 ? -a : a; 07cout << "processing abs : " << ret << endl; 08return ret; 09} 10 11int main(int argc, char* argv[])absabsabsabs 함수를함수를함수를함수를일반화한다일반화한다일반화한다일반화한다.... 11int main(int argc, char* argv[]) 12{ 13int x1=10; 14float x2=-10.1f; 15double x3=-2.3; 16 17generic_abs( x1 ); 18generic_abs( x2 ); 19generic_abs( x3 ); 20 21return 0; 22}
generic_absgeneric_absgeneric_absgeneric_abs 함수에함수에함수에함수에intintintint형을형을형을형을넣어본다넣어본다넣어본다넣어본다.... generic_absgeneric_absgeneric_absgeneric_abs 함수에함수에함수에함수에floatfloatfloatfloat형을형을형을형을넣어본다넣어본다넣어본다넣어본다.... generic_absgeneric_absgeneric_absgeneric_abs 함수에함수에함수에함수에doubledoubledoubledouble형을형을형을형을넣어본다넣어본다넣어본다넣어본다
[응용예제 13 - 2] 일반 함수의 사용 # 2
01#include<iostream> 02using namespace std; 03[①] <typename T> [②] generic_inc([②] a) 04{ 05a+=1; 06cout << "generic_inc result : " << a << endl; 07return a; 08} 09 10int main(int argc, char* argv[]) 11{incincincinc 함수를함수를함수를함수를일반화한다일반화한다일반화한다일반화한다.... 11{ 12int x1=10; 13float x2=5.1f; 14double x3=-2.3; 15 16generic_inc( x1 ); 17generic_inc( x2 ); 18generic_inc( x3 ); 19 20return 0; 21}
generic_incgeneric_incgeneric_incgeneric_inc 함수에함수에함수에함수에intintintint형을형을형을형을넣어본다넣어본다넣어본다넣어본다.... generic_incgeneric_incgeneric_incgeneric_inc 함수에함수에함수에함수에floatfloatfloatfloat형을형을형을형을넣어본다넣어본다넣어본다넣어본다.... generic_incgeneric_incgeneric_incgeneric_inc 함수에함수에함수에함수에doubledoubledoubledouble형을형을형을형을넣어본다넣어본다넣어본다넣어본다....
[기본예제 13 - 3] 일반 함수의 사용 # 3
01#include<iostream> 02using namespace std; 03template <typename T> T avg(T a, T b) 04{ 05T ret = (a+b)/2; 06cout << "avg = " << ret << endl; 07return ret; 08} 09 10int main(int argc, char* argv[]) 11{avgavgavgavg 함수를함수를함수를함수를일반화한다일반화한다일반화한다일반화한다.... 11{ 12int x1=10; 13int x2=0; 14float x3=5.1f; 15 16avg( x1, x2 ); 17avg( x1, x3 ); 18 19return 0; 20}
(int, int)(int, int)(int, int)(int, int)를를를를입력으로입력으로입력으로입력으로넣는다넣는다넣는다넣는다.... (int, float)(int, float)(int, float)(int, float)을을을을입력으로입력으로입력으로입력으로넣는다넣는다넣는다넣는다
<<<< 에 러 에 러 에 러 에 러 메 시 지 메 시 지 메 시 지 메 시 지 >>>> te m p la te p a ra m e te r ‘T ’ is a m b ig u o u s c o u ld b e ‘ fl o a t’ o r ‘ in t’
[응용예제 13 - 4] 일반 함수의 사용 # 4
01#include<iostream> 02using namespace std; 03template < [①] T1, [①] T2> T avg(T1 a, T2 b) 04{ 05T1 ret = (a+b)/2; 06cout<< "avg= " << ret << endl; 07return ret; 08} 09 10intmain(intargc, char* argv[]) 11{ 12intx1=10;avgavgavgavg 함수를함수를함수를함수를일반화한다일반화한다일반화한다일반화한다.... 12intx1=10; 13intx2=0; 14float x3=5.1f; 15 16avg( x1, x2 ); 17avg( x1, x3 ); // avg<int, int>(x1,x2); // avg<float, float>(x1,x3); 도가능함 18 19return 0; 20}
(int, int)(int, int)(int, int)(int, int)를를를를입력으로입력으로입력으로입력으로넣는다넣는다넣는다넣는다.... (int, float)(int, float)(int, float)(int, float)을을을을입력으로입력으로입력으로입력으로넣는다넣는다넣는다넣는다....
02_ 일반 클래스 (클래스 템플릿 ) 일반 클래스 일반 함수와 마찬가지로 일반 클래스도 정의할 수가 있다 . 일반 클래스를 정의하는 방법은 다음과 같다 . te m p la te < ty p e n a m e T > c la s s 클래스명 ; e x . te m p la te < ty p e n a m e T > c la s s s ta c k ; 일반 클래스의 인스턴스를 만드는 방법은 다음과 같다 . 클래스명 < ty p e > 인스턴스명 ; e x . s ta c k < in t> o In s ta n c e ;
[기본예제 13 - 5] 일반 클래스의 사용
01#include<iostream> 02#define MAX_SIZE 50 03 usingnamespace std; 04template <class T> class stack { 05T data[MAX_SIZE]; 06int nCount; 07public: 08stack() { nCount = 0; } 09void add(T in) { 10data[nCount++] = in; // 이연산전에if 문있어야함 11if (nCount == MAX_SIZE) { 12cerr << "overflow : " << nCount << endl; // 예외상황 13}TTTT에에에에대한대한대한대한스택을스택을스택을스택을 선언한다선언한다선언한다선언한다.... 스택에스택에스택에스택에추가하는추가하는추가하는추가하는(add)(add)(add)(add) 함수를함수를함수를함수를구현한다구현한다구현한다구현한다.... 13} 14} 15T pop(void) { 16if ( nCount <= 0 ) { 17cerr << "empty" << endl; 18return data[0]; // 이건의미없음(원래라면예외) 19} 20else { 21return data[--nCount]; 22} 23} 24}; 25 스택에서스택에서스택에서스택에서꺼내는꺼내는꺼내는꺼내는(pop)(pop)(pop)(pop) 함수를함수를함수를함수를구현한다구현한다구현한다구현한다....
[기본예제 13 - 5] 일반 클래스의 사용 co n t’
26int main(int argc, char* argv[]) 27{ 28stack<int> stack1; 29stack<float> stack2; 30int i; 31float j; 32 33for(i=0;i<10;i++) { 34stack1.add( i ); 35} 36for(j=0;j<10;j+=.4) { 37stack2.add( j ); 38}38} 39 40cout << "Stack1 : "; 41for(i=0;i<10;i++) { 42cout << stack1.pop() << " "; 43} 44cout << endl << "Stack2 : "; 45for(i=0;i<10;i++) { 46cout << stack2.pop() << " "; 47} 48cout << endl; 49 50return 0; 51}예제모음 _25 의 요구사항 및 실행결과 요 구 사 항 요 구 사 항 요 구 사 항 요 구 사 항 ① 다음의 s w a p 함수를 일반화시켜라 . v o id s w a p (i n t& a , in t& b ) { in t te m p ; te m p = a ; a = b ; b = t e m p ; }} 실 행 결 과 실 행 결 과 실 행 결 과 실 행 결 과
예제모음 _25 소스
01#include<iostream> 02usingnamespace std; 03template <typename T> void generic_swap(T& a, T& b) 04{ 05T temp; 06temp = a; 07a = b; 08b = temp; 09} 10 11int main()swapswapswapswap 함수를함수를함수를함수를 일반화일반화일반화일반화시킨다시킨다시킨다시킨다.... 11int main() 12{ 13int a=57, b=2; 14cout << "a = " << a << ", b = " << b << endl; 15generic_swap( a, b ); 16cout << "after swap : a = " << a << ", b = " << b << endl; 17 18double c=5.7, d=2.3; 19cout << "c = " << c << ", d = " << d << endl; 20generic_swap( c, d ); 21cout << "after swap : c = " << c << ", d = " << d << endl; 22 23return 0; 24}
intintintint형에형에형에형에대한대한대한대한 테스트를테스트를테스트를테스트를수행한다수행한다수행한다수행한다 doubledoubledoubledouble형에형에형에형에대한대한대한대한 테스트를테스트를테스트를테스트를수행한다수행한다수행한다수행한다
예제모음 _26 의 요구사항 및 실행결과 요 구 사 항 요 구 사 항 요 구 사 항 요 구 사 항 ① 다음과 같은 in t형에 대한 li s t 클래스가 있다 . 이 클래스를 모든 변수형에 대해서 동작할 수 있도록 일반화시켜라 .
01class list { 02int data; 03list *pNext; 04public: 05list(int a){ 06data=a; 07pNext=NULL;07pNext=NULL; 08} 09void add(list *pNode){ 10pNode->pNext = this; 11pNext = NULL; 12} 13list* getNext(){ 14return pNext; 15} 16int getData(){ 17return data; 18} 19};실 행 결 과 실 행 결 과 실 행 결 과 실 행 결 과
예제모음 _26 소스
01#include<iostream> 02using namespace std; 03template <class T>class list { 04T data; 05list *pNext; 06public: 07list(T a){ 08data=a; 09pNext=NULL; 10} 11void add(list *pNode){생성자를생성자를생성자를생성자를구현한다구현한다구현한다구현한다.... listlistlistlist에에에에추가하는추가하는추가하는추가하는(add)(add)(add)(add)11void add(list *pNode){ 12pNode->pNext = this; 13pNext = NULL; 14} 15list* getNext(){ 16return pNext; 17} 18T getData(){ 19return data; 20} 21}; 22
다음다음다음다음노드를노드를노드를노드를반환하반환하반환하반환하 함수를함수를함수를함수를구현한다구현한다구현한다구현한다.... 현재현재현재현재노드의노드의노드의노드의값을값을값을값을 반환하는반환하는반환하는반환하는함수를함수를함수를함수를 구현한다구현한다구현한다구현한다....
listlistlistlist에에에에추가하는추가하는추가하는추가하는(add)(add)(add)(add) 함수를함수를함수를함수를구현한다구현한다구현한다구현한다....
예제모음 _26 소스 co n t’
23int main() 24{ 25list<int> List1(0); 26list<int> *pNode, *pLast; 27 28pLast = &List1; 29for(int i=1;i<=10;i++) { 30pNode = new list<int>(i); 31pNode->add( pLast ); 32pLast = pNode; 33}1111에서에서에서에서10101010까지의까지의까지의까지의정수에정수에정수에정수에 대한대한대한대한리스트리스트리스트리스트노드를노드를노드를노드를 생성하고생성하고생성하고생성하고, , , , 연결한다연결한다연결한다연결한다.... 33} 34 35pNode = &List1; 36while(pNode) { 37cout << pNode->getData() << endl; 38pNode = pNode->getNext(); 39} 40 41return 0; 42}
리스트에리스트에리스트에리스트에들어있는들어있는들어있는들어있는 데이터를데이터를데이터를데이터를처음부터처음부터처음부터처음부터 끝가지끝가지끝가지끝가지순회하며순회하며순회하며순회하며 출력한다출력한다출력한다출력한다....
요약 일반화일반화
일반화(템플릿)란구조가동일한경우에대해내용물을바꾸기만하면같은 모양으로만들어지는틀을만드는작업과동일한데, 이를함수에적용한것을 일반함수(함수템플릿)라부르며, 클래스에적용한것을일반클래스(클래스 템플릿)라부른다.일반일반 함수의함수의 정의정의
te m p la te < ty p e n a m e T > te m p la te < ty p e n a m e T > te m p la te < ty p e n a m e T > te m p la te < ty p e n a m e T > 반 환 값 반 환 값 반 환 값 반 환 값 함 수 명 함 수 명 함 수 명 함 수 명 ((((입 력 인 자 입 력 인 자 입 력 인 자 입 력 인 자 )))) {{{{ 문 장 문 장 문 장 문 장 ... . ... }}}} 일반일반 클래스의클래스의 정의정의
일반클래스는다음과같이정의한다. template <class T> class template <class T> class template <class T> class template <class T> class 클래스명클래스명클래스명클래스명;;;; ex. template <class T> class stack;ex. template <class T> class stack;ex. template <class T> class stack;ex. template <class T> class stack; 일반클래스에서인스턴스를만드는방법은다음과같다. 클래스명클래스명클래스명클래스명<type><type><type><type> 인스턴스명인스턴스명인스턴스명인스턴스명;;;; ex. stack <int> oInstance;ex. stack <int> oInstance;ex. stack <int> oInstance;ex. stack <int> oInstance;