
[문과 코린이의 IT 기록장] C++ - 클래스 템플릿(Class Template) (클래스 템플릿의 정의, 클래스 템플릿의 선언과 정의의 분리, 배열 클래스의 템플릿화)
1. 클래스 템플릿의 정의
[문과 코린이의 IT 기록장] C,C++ - 템플릿(Template)에 대한 이해와 함수 템플릿 (함수를 대상으로 템
[문과 코린이의 IT 기록장] C,C++ - 템플릿(Template)에 대한 이해와 함수 템플릿 (함수를 대상으로 템플릿 이해하기, 함수 템플릿과 템플릿 함수, 둘 이상의 형(Type)에 대해 템플릿
vansoft1215.tistory.com
* 이전의 내용처럼 함수를 템플릿으로 정의했듯이, 클래스도 템플릿으로 정의가 가능하다.
[문과 코린이의 IT 기록장] C,C++ - 연산자 오버로딩 5 : 배열의 인덱스 연산자 오버로딩 (배열 클래
[문과 코린이의 IT 기록장] C,C++ - 연산자 오버로딩 4 : 배열의 인덱스 연산자 오버로딩 (배열 클래스, const 함수를 이용한 오버로딩의 활용, 객체의 저장을 위한, 배열 클래스의
vansoft1215.tistory.com
- 위 포스팅에서 다음과 같은 클래스를 정의한 바 있다.
class BoundCheckIntArray { ... }; class BoundCheckPointArray { ... }; class BoundCheckPointPtrArray { ... };
이들은 모두 배열 클래스들이다. 그러나, 저장의 대상이 달라 세 개나 따로 정의할 수밖에 없었다.
- 이럴 때는 클래스 템플릿을 정의하여 문제를 해결할 수 있다.
ex 1 ) 기존 Point 클래스
class Point { private: int xpos, ypos; public: Point(int x = 0, int y = 0) : xpos(x), ypos(y) { } void ShowPosition() const { // const 변수를 함수 내부에서 사용할 수 있지만, 값에 대한 변경은 방지한다. cout << '[' << xpos << ", " << ypos << ']' << endl; } };
ex 2 ) Point 클래스를 클레스 탬플릿으로 변환
template <typename T> class Point { private: T xpos, ypos; public: Point(T x = 0, T y = 0) : xpos(x), ypos(y) { } void ShowPosition() const { // const 변수를 함수 내부에서 사용할 수 있지만, 값에 대한 변경은 방지한다. cout << '[' << xpos << ", " << ypos << ']' << endl; } };
* 클래스 템플릿의 정의방법은 함수 템플릿의 정의방법과 동일하다.
Case 1 )
#include<iostream> using namespace std; template <typename T> class Point { private: T xpos, ypos; public: Point(T x = 0, T y = 0) : xpos(x), ypos(y) { } void ShowPosition() const { // const 변수를 함수 내부에서 사용할 수 있지만, 값에 대한 변경은 방지한다. cout << '[' << xpos << ", " << ypos << ']' << endl; } }; int main() { Point <int>pos1(3, 4); // T를 <int>로 하여 만든 템플릿 클래스 pos1.ShowPosition(); Point <double>pos2(2.4, 3.6); // T를 <double>로 하여 만든 템플릿 클래스 pos2.ShowPosition(); // 좌표정보를 문자로 표시하는 상황의 표현 Point <char> pos3('P', 'F'); // T를 <char>로 하여 만든 템플릿 클래스 pos3.ShowPosition(); return 0; }

- 함수 템플릿과 마찬가지로, '클래스 템플릿'을 기반으로 '템플릿 클래스'를 만들어낸다.
Point <int> 템플릿 클래스
Point <double> 템플릿 클래스
Point <char> 템플릿 클래스
- 템플릿 클래스는 템플릿 함수와 달리, 객체 생성 시 자료형 정보(ex. <int>, <double>)를 꼭 명시해주어야 한다.
2. 클래스 템플릿의 선언과 정의의 분리
- 클래스 템플릿도 맴버함수를 클래스 외부에 정의하는 것이 가능하다.
ex )
template <typename T> class SimpleTemplate { public: T SimpleFunc(const T& ref); } (중략) template <typename T> // 꼭 써줘야 함 T SimpleTemplate<T> :: SimpleFunc(const T ref) { ... }
SimpleTemplate<T> : T에 대해 템플릿화 된, SimpleTemplate 클래스 템플릿
Case 2 )
#include<iostream> using namespace std; template <typename T> class Point { private: T xpos, ypos; public: Point(T x = 0, T y = 0); void ShowPosition() const; }; template <typename T> Point<T>::Point(T x, T y):xpos(x), ypos(y) { } // T에 대해 템플릿화 된, Point 클래스 템플릿 template <typename T> void Point<T> :: ShowPosition() const { cout << '[' << xpos << ", " << ypos << ']' << endl; } // T에 대해 템플릿화 된, Point 클래스 템플릿 int main() { Point <int>pos1(3, 4); pos1.ShowPosition(); Point <double>pos2(2.4, 3.6); pos2.ShowPosition(); Point <char> pos3('P', 'F'); pos3.ShowPosition(); return 0; }
3. 배열 클래스의 템플릿화
[ ArrayTemplate. H ]
#pragma once #ifndef __ ARRAY_TEMPLATE_H_ #define __ ARRAY_TEMPLATE_H_ #include<iostream> #include<cstdlib> template <typename T> class BoundCheckArray { private: T* arr; int arrlen; /* 깊은 복사가 진행될 수 있도록, 복사생성자와 대입연산자를 private 맴버로 두면서 복사와 대입을 막는다.*/ // 배열은 저장소의 일종이며, 저장소에 저장된 데이터는 '유일성'이 보장되어야 하기 때문에, 대부분의 경우 배열에서의 복사는 불필요하거나 잘못된 일로 간주하곤 한다. BoundCheckArray(const BoundCheckArray& arr) { } // 복사생성자 BoundCheckArray& operator=(const BoundCheckArray& arr) { } // 대입연산자 public: BoundCheckArray(int len); // 생성자 T& operator[] (int idx); // 배열 연산자 T operator[](int idx)const; // const 배열 연산자 int GetArrLen() const; // arrlen : 배열의 길이 반환 함수 ~BoundCheckArray(); // 소멸자 }; #endif
[ ArrayTemplate.cpp ]
#include "ArrayTemplate.h" #include<iostream> using namespace std; template<typename T> BoundCheckArray<T>::BoundCheckArray(int len) :arrlen(len) { // 생성자 arr = new T[len]; // 힙에 배열만큼의 메모리 공간 마련 } template<typename T> T& BoundCheckArray<T>::operator[] (int idx) { // 배열 연산자 /* iarr[i] = iarr.operator[](i) */ if (idx < 0 || idx >= arrlen) { // 잘못된 배열 접근을 막기 위한, 안전성 보장 코드 cout << "Array index out of bound exception" << endl; exit(1); // 에러시 강제 종료 } return arr[idx]; // 배열 요소의 참조값이 반환됨 } template<typename T> T BoundCheckArray<T>::operator[] (int idx) const { // const 맴버함수 추가 배열 연산자 // const 매개변수가 있는 함수가 사용될 예정인 경우, operator[]함수 또한 const로 사용되어야 한다. // 따라서 이러한 경우 따로 정의를 해 줄 필요가 있다. if (idx < 0 || idx >= arrlen) { cout << "Array index out of bound exception" << endl; exit(1); } return arr[idx]; } template <typename T> int BoundCheckArray<T>::GetArrLen() const { // 배열의 길이 반환 함수 return arrlen; } template <typename T> BoundCheckArray<T>::~BoundCheckArray() { // 소멸자 delete[]arr; // 배열 메모리 해제 }
[ Point.h ]
#pragma once #ifndef __POINT_H_ #define __POINT_H_ #include<iostream> using namespace std; class Point { private: int xpos, ypos; public: Point(int x = 0, int y = 0); // 생성자 friend ostream& operator<<(ostream& os, const Point& pos); // Point 객체의, cout 연산을 위해 }; #endif
[ Point.cpp ]
#include "Point.h" Point::Point(int x, int y) :xpos(x), ypos(y) { } ostream& operator<<(ostream& os, const Point& pos) { os << '[' << pos.xpos << ", " << pos.ypos << ']' << endl; return os; }
[ Main ]
#include <iostream> #include "Point.h" #include "ArrayTemplate.h" #include "ArrayTemplate.cpp" using namespace std; int main() { /* int형 정수 저장 */ BoundCheckArray<int> iarr(5); for(int i = 0; i <5; i++) { iarr[i] = (i + 1) * 11; } for (int i = 0; i < 5; i++) { cout << iarr[i] << endl; } /* Point 객체 저장 */ BoundCheckArray<Point> oarr(3); oarr[0] = Point(3, 4); oarr[1] = Point(5, 6); oarr[2] = Point(7, 8); for (int i = 0; i < oarr.GetArrLen(); i++) { cout << oarr[i]; } /* Point 객체의 주소 값 저장 */ typedef Point* POINT_PTR; // POINT_PTR을 *Point 자료형의 별칭으로 정의한다. // 즉 Point 포인터 형 = POINT_PTR // 저장의 대상, 또는 연산의 주 대상이 포인터인 경우, 이렇듯 별도의 자료형을 정의하는 것이 좋다. BoundCheckArray<POINT_PTR> parr(3); // parr은 포인터의 포인터 parr[0] = new Point(3, 4); parr[1] = new Point(5, 6); parr[2] = new Point(7, 8); for (int i = 0; i < parr.GetArrLen(); i++) { cout << *(parr[i]); } delete parr[0]; delete parr[1]; delete parr[2]; return 0; }

* 유의사항 - 아직 공부하고 있는 문과생 코린이가, 정리해서 남겨놓은 정리 및 필기노트입니다. - 정확하지 않거나, 틀린 점이 있을 수 있으니, 유의해서 봐주시면 감사하겠습니다. - 혹시 잘못된 점을 발견하셨다면, 댓글로 친절하게 남겨주시면 감사하겠습니다 :) |