기본적인 내용은 2장의 함수 템플릿과 동일하나, 인스턴스 선언시에는 typename
을 반드시 기술해야 한다는 점이 다르다.
선언 방법
template<typename T>
class Example {
...
}
다음 예제를 통해 클래스 템플릿의 활용을 알아보자.
#include <iostream>
using namespace std;
templcate<typename T>
class CMyArray {
public:
explicit CMyArray(int nSize): m_nSize(nSize) {
m_pData = new T[nSize];
}
~CMyArray() { delete[] m_pData; }
// 복사 생성자
CMyArray(const CMyArray &rhs) {
m_pData = new T[rhs.m_nSize];
memcpy(m_pData, rhs.m_pData, sizeof(T)*rhs.m_nSize);
}
// 대입 연산자
CMyArray& operator=(const CMyArray &rhs) {
if(this == &rhs) {
return *this;
}
delete m_pData;
m_pData = new T[rhs.m_nSize];
memcpy(m_pData, rhs.m_pData, sizeof(T)*rhs.m_nSize);
return *this;
}
// 이동 생성자
CMyArray(const CMyArray &&rhs) {
operator = (rhs); // ??
}
// 이동 대입 연산자
CMyArray& operator=(const CMyArray &&rhs) {
m_pData = rhs.m_pData;
m_nSize = rhs.m_nSize;
rhs.m_pData = nullptr;
rhs.m_nSize = 0;
}
// 배열 연산자
T& operator[](int Index) {
if(nIndex < 0 || nIndex >= m_nSize) {
cout << "ERROR: Array out of index." << endl;
exit(1);
}
return m_pData[nIndex];
}
// 상수화된 배열 연산자
T& operator[](int Index) const {
return operator[](nIndex);
}
int GetSize() { return m_nSize; }
private:
T *m_pData = nullptr;
int m_nSize = 0;
}
int main(int argc, char* argv[]) {
CMyArray<int> arr(5);
arr[0] = 10;
arr[1] = 20;
arr[2] = 30;
arr[3] = 40;
arr[4] = 50;
for(int i=0;i<5;++i) {
cout << arr[i] << ' ';
}
cout << endl;
CMyArray<int> arr2(3);
arr2 = arr;
for(int i=0;i<5;++i) {
cout << arr2[i] << ' ';
}
cout << endl;
}
template<typename T>
를 매번 선언해야 한다는 단점이 있다.// 템플릿 매개변수를 함수처럼 이용할 수 있다.
template<typename T, int nSize>
class Example1 {
public:
CMyArray() { m_pData = new T[nSize]; }
private:
T *m_pData = nullptr;
}
// 형식을 여러 개 작성할 수 있고, 매개변수의 기본값을 둘 수도 있다.
template<typename T1 = int, typename T2 = int>
class Example2 {
public:
CMyArray(T1 p1, T2 p2) {
data1 = p1;
data2 = p2;
}
private:
T1 data1;
T2 data2;
}
다음과 같이 형식에 따라 함수 구현을 나눌 수 있다.
#include <memory>
#include <iostream>
using namespace std;
template<typename T>
T Add(T a, T b) { return a + b; }
// 두 개의 변수가 모두 char* 형식이면 이 함수로 대체된다.
template< >
char* Add(char *pszLeft, char *pszRight) {
int nLenLeft = strlen(pszLeft);
int nLenRight = strlen(pszRight);
char *pszResult = new char[nLenLeft + nLenRight + 1];
strcpy(pszResult, pszLeft);
strcat(pszResult, pszRight);
return pszResult;
}
int main(int argc, char* argv[]) {
int nResult = Add<int>(3, 4);
char *pszResult = Add<char*>("Hello", "World");
delete[] pszResult;
return 0;
}
템플릿을 특수화 할 때, typename
을 기술하지 않는것이 관례다.
template< >
으로 특정 타입에 대한 클래스 별도 선언.template<typename T>
class Parent {
...
}
template<typename T>
class Child: public Parent<T> {
...
}
auto_ptr
: 동적 할당한 인스턴스를 자동으로 삭제한다.shared_ptr
: 포인팅 횟수를 계수해서 0이 되면 대상을 삭제한다. -> gc랑 비슷한거 아님??unique_ptr
: shared_ptr
과 달리 한 대상을 한 포이터로만 포인팅한다. 즉, 하나의 소유자만 허용한다.weak_ptr
: 하나 이상의 shared_ptr
인스턴스가 소유하는 개체에 접근할 수 있게 하지만, 참조 수로 계산하지 않는다.auto_ptr
shared_ptr
shared_ptr<Example> ptr(new Example(3), [](Example *ex) { delete[] ex; })
unique_ptr