공부 중 메모/수업 예제 (KGCA)

Cpp 클래스 템플릿 부분 특수화 예제

라이피 (Lypi) 2018. 7. 16. 19:01
반응형

출처 : KGCA 게임 아카데미(http://www.kgcaschool.com/). 수업 예제 파일.


OriginalTemplate.h

#pragma once

// 어차피 멤버 함수를 클래스 템플릿 외부에 정의해서 다른 파일로 분리할 수 없으니
// 클래스 템플릿 안에다가 인라인으로 넣어버림.


// 기본 타입 클래스 템플릿
template <class T>
class Bag
{
	T* elem;
	int size;
	int max_size;

public:
	
	void add(T t)
	{
		T* tmp;
		if (size + 1 >= max_size)	{
			max_size *= 2;
			tmp = new T[max_size];
			for (int iCnt = 0; iCnt < size; iCnt++) {
				tmp[iCnt] = elem[iCnt];
			}
			tmp[size++] = t;
			delete[] elem;
			elem = tmp;
		}
		else {
			elem[size++] = t;
		}
	}

	void print()
	{
		for (int iCnt = 0; iCnt < size; iCnt++) {
			cout << elem[iCnt] << " ";
		}
		cout << endl << endl;
	}

	void sort()
	{
		for (int a = 1; a<size; a += 1)
		{
			int temp = elem[a];
			int b = a - 1;
			while (b >= 0 && elem[b] > temp)
			{
				elem[b + 1] = elem[b];
				b -= 1;
			}
			elem[b + 1] = temp;
		}
	}

	Bag() : elem(0), size(0), max_size(1) {}

};

// 포인터 타입 클래스 템플릿에 대한 부분 특수화
// NULL을 검사하도록 (컬렉션이 수정 및 저장소 유형
template <class T>
class Bag<T*>
{
	T* elem;
	int size;
	int max_size;

public:

	void add(T* t)
	{
		T* tmp;

		if (t == nullptr)
		{
			//check for nullptr
			cout << "Null pointer!" << endl;
			return;
		}

		if (size + 1 >= max_size) {
			max_size *= 2;
			tmp = new T[max_size];
			for (int iCnt = 0; iCnt < size; iCnt++) {
				tmp[iCnt] = elem[iCnt];
			}
			tmp[size++] = *t; //Dereference
			delete[] elem;
			elem = tmp;
		}
		else {
			elem[size++] = *t; //Dereference
		}
	}

	void print()
	{
		for (int iCnt = 0; iCnt < size; iCnt++) {
			cout << elem[iCnt] << " ";
		}
		cout << endl << endl;
	}

	void sort()
	{
		for (int a = 1; a<size; a += 1)
		{
			int temp = elem[a];
			int b = a - 1;
			while (b >= 0 && elem[b] > temp)
			{
				elem[b + 1] = elem[b];
				b -= 1;
			}
			elem[b + 1] = temp;
		}
	}

	Bag() : elem(0), size(0), max_size(1) {}

};

Dictionary.h

#pragma once
#include <iostream>
#include <string>
using namespace std;

//클래스 템플릿
template <class key, class value> class dictionary
{
	key* keys;
	value* values;
	int size;
	int max_size;

public:
	void add(key k, value v);
	void print();

	dictionary(int initial_size);
	
};

//클래스 템플릿 부분 특수화 
template <class value> class dictionary<int, value>
{
	int* keys;
	value* values;
	int size;
	int max_size;

public:
	void add(int key, value v);
	void print();
	void sort();

	dictionary(int initial_size);
};


//클래스 템플릿의 멤버 함수를 cpp파일에 따로 정의할 경우 
//확인할 수 없는 외부기호라는 링크 에러가 뜬다.
//이에 대한 자세한 내용은 템플릿이 클래스를 어떻게 만드는지와 
//obj파일이 어떻게 생성되는지에 대해서 확인할 것.

//클래스 템플릿 멤버 함수 정의

template<class key, class value>
dictionary<key, value>::dictionary(int initial_size) : size(0) {
	max_size = 1;
	while (initial_size >= max_size) {
		max_size *= 2;
	}
	keys = new key[max_size];
	values = new value[max_size];
}

template<class key, class value>
void dictionary<key, value>::add(key k, value v)
{
	key* tmpKey;
	value* tmpVal;

	if (size + 1 >= max_size) {
		max_size *= 2;
		tmpKey = new key[max_size];
		tmpVal = new value[max_size];

		for (int iCnt = 0; iCnt < size; iCnt++) {
			tmpKey[iCnt] = keys[iCnt];
			tmpVal[iCnt] = values[iCnt];
		}

		tmpKey[size] = k;
		tmpVal[size] = v;

		delete[] keys;
		delete[] values;

		keys = tmpKey;
		values = tmpVal;
	}

	else {
		keys[size] = k;
		values[size] = v;
	}
	size++;
}

template<class key, class value>
void dictionary<key, value>::print()
{
	for (int iCnt = 0; iCnt < size; iCnt++) {
		cout << "{" << keys[iCnt] << ", " << values[iCnt] << "}" << endl;
	}
	cout << endl;
}

//특수화 한 클래스 템플릿 멤버 함수 정의

template <class value>
dictionary<int, value>::dictionary(int initial_size)
{
	max_size = 1;
	while (initial_size >= max_size) {
		max_size *= 2;
	}
	keys = new int[max_size];
	values = new value[max_size];
}

template <class value>
void dictionary<int, value>::add(int key, value v)
{
	int* tmpKey;
	value* tmpVal;

	if (size + 1 >= max_size) {
		max_size *= 2;
		tmpKey = new int[max_size];
		tmpVal = new value[max_size];

		for (int iCnt = 0; iCnt < size; iCnt++) {
			tmpKey[iCnt] = keys[iCnt];
			tmpVal[iCnt] = values[iCnt];
		}

		tmpKey[size] = key;
		tmpVal[size] = v;

		delete[] keys;
		delete[] values;

		keys = tmpKey;
		values = tmpVal;
	}

	else {
		keys[size] = key;
		values[size] = v;
	}
	size++;

}

template <class value>
void dictionary<int, value>::print()
{
	for (int iCnt = 0; iCnt < size; iCnt++) {
		cout << "{" << keys[iCnt] << ", " << values[iCnt] << "}" << endl;
	}
	cout << endl;
}

template <class value>
void dictionary<int, value>::sort()
{
	int smallest = 0;
	for (int iCnt = 0; iCnt < size - 1; iCnt++) {
		for (int jCnt = iCnt; jCnt < size; jCnt++) {
			if (keys[jCnt] < keys[smallest]) {
				smallest = jCnt;
			}
		}
		swap(keys[iCnt], keys[smallest]);
		swap(values[iCnt], values[smallest]);
	}
}

TemplatePartialMain.cpp

#include "Dictionary.h"
#include "OriginalTemplate.h"

int main()
{

	cout << "한개의 데이터를 받는 경우" << endl << endl;

	cout << "int형 클래스 생성 및 테스트" << endl;
	Bag<int> xi;
	xi.add(8);
	xi.add(10);
	xi.add(2);
	xi.print();

	cout << "데이터 정렬" << endl;
	xi.sort();
	xi.print();

	cout << "char형 클래스 생성 및 테스트" << endl;
	Bag<char> xc;
	xc.add('b');
	xc.add('x');
	xc.add('e');
	xc.print();

	cout << "데이터 정렬" << endl;
	xc.sort();
	xc.print();

	cout << "uses partial specialization for pointer types." << endl;
	cout << "int*형 클래스 생성 및 테스트" << endl;

	Bag<int*> xp;
	
	//주소를 받아올 int형 변수 생성
	int* p = new int[2];
	p[0] = 8;
	p[1] = 100;
	int i = 3;
	int j = 87;
	int* pn = nullptr; //nullptr 생성

	xp.add(&i);
	xp.add(&j);
	xp.add(p);
	xp.add(p+1);
	xp.add(pn);   //들어가지 않음
	xp.print();

	cout << "데이터 정렬" << endl;
	xp.sort();
	xp.print();
	
	cout << "두개의 데이터를 받는 경우" << endl << endl;

	cout << "기본 템플릿 클래스 생성 및 테스트" << endl;
	dictionary<string, string>* dict = new dictionary<string, string>(10);
	
	cout << "데이터 한개 입력" << endl;
	dict->add("apple", "fruit");
	dict->print();

	cout << "데이터 세개 입력" << endl;
	dict->add("banana", "fruit");
	dict->add("dog", "animal");
	dict->print();

	cout << "특수화한 템플릿 클래스 생성 및 테스트" << endl;
	dictionary<int, string>* dict_s = new dictionary<int, string>(10);

	cout << "데이터 한개 입력" << endl;
	dict_s->add(100, "apple");
	dict_s->print();

	cout << "데이터 세개 입력" << endl;
	dict_s->add(101, "banana");
	dict_s->add(89, "dog");
	dict_s->add(103 , "cat");
	dict_s->print();

	dict_s->sort();
	cout << "데이터 정렬" << endl;
	cout << "sorted list :" << endl;
	dict_s->print();

}



반응형