1] 템플릿 개념의 확장
1. 클래스 템플릿의 확장
template <class T>
class Point
{
private:
T xpos, ypos;
public:
Point(T x=0, T y=0);
void ShowPosition() const;
};
template <class T>
class BoundCheckArray
{
private:
T *arr;
public:
BoundCheckArray(T);
};
위 클래스 기반으로 Point<int> 템플릿 클래스의 객체를 저장할 수 있는 객체는 어떻게 생성해야할까? 딱히 어렵지 않아 보인다.
BoundCheckArray<Point<int>> pointArr(50);
Point<Int>형 포인터라면, 다음과 같이 객체를 생성하면 된다.
BoundCheckArray<Point<int>*> pointArrPtr(50);
타입이 너무 길다면, typedef 선언으로 간략화 할 수 있다.
typedef Point<int>* POINT_PTR;
* 특정 템플릿 클래스의 객체를 인자로 받는 일반함수의 정의와 friend 선언
: Point<int>와 같은 템플릿 클래스의 자료형을 대상으로도 일반함수의 정의가 가능하고, 클래스 템플릿 내에서 이러한 함수를 대상으로 friend 선언도 가능하다.
2] 클래스 템플릿의 특수화
: 클래스 템플릿의 특수화도 함수 템플릿의 특수화랑 매우 비슷하다.
1. 클래스 템플릿 특수화
: 클래스 템플릿을 특수화하는 이유는, 특정 자료형을 기반으로 생성된 객체에 대해, 구분이 되는 다른 행동양식을 적용하기 위해서이다.
template <class T>
class SoSimple
{
public:
T SimpleFunc(T num)
{
...
}
};
위 클래스의 int형 특수화는 다음과 같다.
template<>
class SoSimple<int>
{
public:
int SimpleFunc(int num)
{
...
}
};
2. 클래스 템플릿의 부분 특수화
template <class T1, class T2>
class MySimple { ... };
다음은 위 클래스 템플릿을 부분 특수화한 코드이다.
template <class T1>
class MySimple<T1, int> { ... }
그렇다. 두개의 템플릿 타입에 대하여 하나의 타입만 특수화를 한것이다.
template <>
class MySimple<double, int> { ... }
위는 전체 타입에 대해 특수화를 시킨것이다. 만약 두개의 정의가 겹치는 즉 MySimple<double, int> 타입의 객체를 생성하려고 하면 전체 특수화에 대한 클래스 템플릿이 우선시 된다.
3] 템플릿 인자
: 위에서 사용된 T 또는 T1, T2 같은 문자를 가리켜 "템플릿 매개변수" 라고 한다. 그리고 템플릿 매개변수에 전달되는 자료형 정보를 가리켜 "템플릿 인자" 라고 한다.
1. 템플릿 매개변수에는 변수의 선언이 올 수 있다.
: 다음의 클래스 템플릿 정의를 보자. 이 정의에서 독특한 사실은 템플릿 매개변수의 선언에 마치 함수처럼 변수의 선언이 등장했다는 점이다.
template <typename T, int len>
class SimpleArray
{
private:
T arr[len];
public:
T& operator[] (int idx)
{
return arr[idx];
}
};
이렇듯 템플릿 매개변수에도 변수가 올 수 있다. 그리고 이를 기반으로 다음의 형태로 객체생성이 가능하다.
SimpleArray<int, 5> i5arr;
SimpleArray<double, 7> d7arr;
위의 두 문장에서 템플릿 매개변수 len에 전달된 인자 5와 7은 해당 템플릿 클래스에서 상수처럼 사용된다. 즉, len은 각각 5와 7로 치환되어 템플릿 클래스가 각각 생성된다.
class SimpleArray<int, 5>
{
private:
int arr[5];
public:
int& operator[] (int idx)
{
return arr[idx];
}
};
class SimpleArray<double, 7>
{
private:
int arr[7];
public:
double& operator[] (int idx)
{
return arr[idx];
}
};
물론, 위의 두 템플릿 클래스 SimpleArray<int, 5>와 SimpleArray<double, 7>은 완전히 다른 타입이다.
위에서 보인 것처럼 배열의 길이를 결정하기 위해서 굳이 위에처럼 하지말고 생성자를 이용해서 하면 더욱 편리할 것이다.
그런데 굳이 이러한 템플릿 클래스를 만드는 이유는, 길이가 다른 두 배열 객체간의 대입 및 복사에 대한 부분을 신경 쓰지 않아도 된다는 것이다. 서로 다른 타입이기 때문에 길이가 다른 배열에 객체에 대해 대입 및 복사 연산을 할 경우 컴파일 에러가 발생할 것이기 때문이다.
만약 생성자를 이용해서 배열의 길이를 결정하게 했다면, 길이가 같은 배열에 대해서만 대입을 허용하기 위해서 추가적인 코드의 삽입이 불가피하며, 이러한 추가적인 코드는 대입 및 복사의 과정에서 CPU가 수행해야 할 일을 늘리는 결과로 이어진다.
2. 템플릿 매개변수는 디폴트 값 지정도 가능하다.
: 템플릿 매개변수에도 디폴트 값의 지정이 가능하다.
template <class T=int, int len=7>
class SimpleArray
{
....
}
SimpleArray <> arr;
4] 템플릿과 static
1. 함수 템플릿과 static 지역변수
template <class T>
void ShowStaticVlaue(void)
{
static T num = 0;
num += 1;
cout << num << endl;
}
위의 함수 템플릿은 다음과 같은 템플릿 함수를 만들어 내며 각각의 함수가 static 변수를 따로 가지고 있다.
void ShowStaticVlaue<int>(void)
{
static int num = 0;
num += 1;
cout << num << endl;
}
void ShowStaticVlaue<long>(void)
{
static long num = 0;
num += 1;
cout << num << endl;
}
2. 클래스 템플릿과 static 멤버변수
template <class T>
class SimpleStaticMem
{
private:
static T mem;
public:
void AddMem(int num)
{
mem += num;
}
void ShowMem()
{
cout<<mem<<endl;
}
};
template <class T>
T SimpleStaticMem<T>::mem = 0; // 템플릿 기반의 static 멤버 초기화 문장이다.
위 클래스 템플릿도 타입 별 static 멤버 변수가 각각 유지된다.
3. 템플릿 static 멤버변수 초기화의 특수화
위에서 다음과 같이 static 멤버변수를 초기화 하였다.
template <class T>
T SimpleStaticMem<T>::mem = 0;
그러면 long 타입만 5로 초기화하고 싶을때는 어떻게 할까? 간단하다.
template <>
long SimpleStaticMem<long>::mem = 5;
'C++' 카테고리의 다른 글
[C++] 템플릿(Template)(1) (0) | 2017.12.25 |
---|---|
[C++] 상속과 다형성 (0) | 2017.12.25 |
[C++] 상속 (0) | 2017.12.25 |
[C++] Friend와 Static 그리고 Const (0) | 2017.12.25 |
[C++] 복사 생성자(Copy Constructor) (0) | 2017.12.23 |