클래스 템플릿 기초
2025. 3. 28. 08:47ㆍProgramming Languages/C++
7.2 클래스 템플릿 기초
7.2.1 클래스 템플릿의 개념
클래스 템플릿은 다양한 데이터 타입에 대해 동일한 클래스 구조를 제공합니다:
#include <iostream>
// 클래스 템플릿 정의
template <typename T>
class Box {
private:
T content;
public:
// 생성자
Box(const T& item) : content(item) {}
// 내용물 설정
void setContent(const T& item) {
content = item;
}
// 내용물 반환
T getContent() const {
return content;
}
// 내용물 출력
void printContent() const {
std::cout << "Box 내용물: " << content << std::endl;
}
};
int main() {
// int 타입의 Box
Box<int> intBox(42);
intBox.printContent();
// double 타입의 Box
Box<double> doubleBox(3.14159);
doubleBox.printContent();
// string 타입의 Box
Box<std::string> stringBox("Hello, Templates!");
stringBox.printContent();
// 내용물 변경
intBox.setContent(100);
intBox.printContent();
return 0;
}
클래스 템플릿을 사용할 때는 항상 템플릿 인수를 명시적으로 지정해야 합니다(예: Box<int>, Box<double> 등).
7.2.2 멤버 함수 정의
클래스 템플릿의 멤버 함수는 클래스 내부 또는 외부에 정의할 수 있습니다:
#include <iostream>
// 클래스 템플릿 선언
template <typename T>
class Array {
private:
T* elements;
int size;
public:
// 생성자 선언
Array(int s);
// 소멸자 선언
~Array();
// 요소 접근 함수 선언
T& operator[](int index);
// 배열 크기 반환 함수 선언
int getSize() const;
};
// 클래스 외부에서 생성자 정의
template <typename T>
Array<T>::Array(int s) : size(s) {
elements = new T[size];
for (int i = 0; i < size; i++) {
elements[i] = T(); // 기본값으로 초기화
}
}
// 소멸자 정의
template <typename T>
Array<T>::~Array() {
delete[] elements;
}
// 연산자 오버로딩 정의
template <typename T>
T& Array<T>::operator[](int index) {
if (index < 0 || index >= size) {
throw std::out_of_range("인덱스가 범위를 벗어났습니다.");
}
return elements[index];
}
// 크기 반환 함수 정의
template <typename T>
int Array<T>::getSize() const {
return size;
}
int main() {
// int 배열 생성
Array<int> intArray(5);
// 배열 요소 설정
for (int i = 0; i < intArray.getSize(); i++) {
intArray[i] = i * 10;
}
// 배열 요소 출력
std::cout << "int 배열 내용:" << std::endl;
for (int i = 0; i < intArray.getSize(); i++) {
std::cout << "intArray[" << i << "] = " << intArray[i] << std::endl;
}
// double 배열 생성
Array<double> doubleArray(3);
doubleArray[0] = 3.14;
doubleArray[1] = 2.71;
doubleArray[2] = 1.41;
// 배열 요소 출력
std::cout << "\ndouble 배열 내용:" << std::endl;
for (int i = 0; i < doubleArray.getSize(); i++) {
std::cout << "doubleArray[" << i << "] = " << doubleArray[i] << std::endl;
}
try {
// 범위를 벗어난 접근
std::cout << intArray[10] << std::endl;
} catch (const std::out_of_range& e) {
std::cerr << "예외 발생: " << e.what() << std::endl;
}
return 0;
}
클래스 템플릿의 멤버 함수를 클래스 외부에 정의할 때는 항상 template <typename T> 접두사와 함께 클래스 이름에 템플릿 매개변수를 명시해야 합니다(Array<T>::함수이름).
7.2.3 클래스 템플릿 특수화
특정 타입에 대해 클래스 템플릿을 다르게 구현해야 할 때 특수화를 사용합니다:
#include <iostream>
#include <string>
// 일반 클래스 템플릿
template <typename T>
class DataHolder {
private:
T data;
public:
DataHolder(const T& value) : data(value) {}
void display() const {
std::cout << "일반 데이터: " << data << std::endl;
}
T getValue() const {
return data;
}
};
// char* 타입에 대한 특수화
template <>
class DataHolder<char*> {
private:
char* data;
public:
DataHolder(char* value) {
// 문자열 복사 (깊은 복사)
size_t len = strlen(value) + 1;
data = new char[len];
strcpy(data, value);
}
~DataHolder() {
delete[] data;
}
void display() const {
std::cout << "문자열 데이터: " << data << " (길이: " << strlen(data) << ")" << std::endl;
}
const char* getValue() const {
return data;
}
};
// std::string 타입에 대한 특수화
template <>
class DataHolder<std::string> {
private:
std::string data;
public:
DataHolder(const std::string& value) : data(value) {}
void display() const {
std::cout << "std::string 데이터: " << data << " (길이: " << data.length() << ")" << std::endl;
}
std::string getValue() const {
return data;
}
// 추가 기능
void toUpperCase() {
for (size_t i = 0; i < data.length(); i++) {
data[i] = std::toupper(data[i]);
}
}
};
int main() {
// 일반 템플릿 사용
DataHolder<int> intHolder(42);
intHolder.display();
// char* 특수화 사용
char text[] = "Hello, World";
DataHolder<char*> charHolder(text);
charHolder.display();
// std::string 특수화 사용
DataHolder<std::string> stringHolder("C++ Templates");
stringHolder.display();
// std::string 특수화의 추가 기능 사용
stringHolder.toUpperCase();
stringHolder.display();
return 0;
}
클래스 템플릿 특수화를 통해 특정 타입에 맞는 최적화나 특별한 동작을 구현할 수 있습니다.
7.2.4 부분 특수화
클래스 템플릿의 부분 특수화는 템플릿 매개변수의 일부만 특수화하는 것입니다:
#include <iostream>
// 기본 템플릿 (두 개의 타입 매개변수)
template <typename T, typename U>
class Pair {
private:
T first;
U second;
public:
Pair(const T& f, const U& s) : first(f), second(s) {}
void display() const {
std::cout << "일반 템플릿 - 첫 번째: " << first << ", 두 번째: " << second << std::endl;
}
T getFirst() const { return first; }
U getSecond() const { return second; }
};
// T와 U가 같은 타입일 때의 부분 특수화
template <typename T>
class Pair<T, T> {
private:
T first;
T second;
public:
Pair(const T& f, const T& s) : first(f), second(s) {}
void display() const {
std::cout << "동일 타입 특수화 - 첫 번째: " << first << ", 두 번째: " << second << std::endl;
}
T getFirst() const { return first; }
T getSecond() const { return second; }
// 두 값이 같은지 비교하는 추가 기능
bool areEqual() const {
return first == second;
}
};
// 포인터 타입에 대한 부분 특수화
template <typename T, typename U>
class Pair<T*, U*> {
private:
T* first;
U* second;
public:
Pair(T* f, U* s) : first(f), second(s) {}
void display() const {
std::cout << "포인터 특수화 - 첫 번째: " << *first << ", 두 번째: " << *second << std::endl;
}
T* getFirst() const { return first; }
U* getSecond() const { return second; }
};
int main() {
// 일반 템플릿 사용
Pair<int, double> p1(42, 3.14);
p1.display();
// 동일 타입 특수화 사용
Pair<int, int> p2(10, 20);
p2.display();
std::cout << "두 값이 같나요? " << (p2.areEqual() ? "예" : "아니오") << std::endl;
// 포인터 특수화 사용
int x = 5, y = 10;
Pair<int, int> p3(&x, &y);
p3.display();
return 0;
}
부분 특수화는 보다 구체적인 타입 패턴에 대해 최적화된 구현을 제공할 때 유용합니다.
7.2.5 템플릿 매개변수의 기본값
템플릿 매개변수에도 기본값을 지정할 수 있습니다:
#include <iostream>
// 기본 타입 매개변수를 가진 클래스 템플릿
template <typename T = int, int Size = 10>
class SimpleArray {
private:
T data[Size];
public:
SimpleArray() {
for (int i = 0; i < Size; i++) {
data[i] = T(); // 기본값으로 초기화
}
}
void setAt(int index, const T& value) {
if (index >= 0 && index < Size) {
data[index] = value;
}
}
T getAt(int index) const {
if (index >= 0 && index < Size) {
return data[index];
}
return T();
}
int getSize() const {
return Size;
}
};
int main() {
// 기본 매개변수 사용 (int 타입, 크기 10)
SimpleArray<> array1;
for (int i = 0; i < array1.getSize(); i++) {
array1.setAt(i, i * 10);
}
std::cout << "array1 내용 (기본 매개변수):" << std::endl;
for (int i = 0; i < array1.getSize(); i++) {
std::cout << array1.getAt(i) << " ";
}
std::cout << std::endl;
// 타입만 지정 (double 타입, 크기 10)
SimpleArray<double> array2;
for (int i = 0; i < array2.getSize(); i++) {
array2.setAt(i, i * 1.1);
}
std::cout << "array2 내용 (double 타입):" << std::endl;
for (int i = 0; i < array2.getSize(); i++) {
std::cout << array2.getAt(i) << " ";
}
std::cout << std::endl;
// 모든 매개변수 지정 (char 타입, 크기 5)
SimpleArray<char, 5> array3;
array3.setAt(0, 'H');
array3.setAt(1, 'e');
array3.setAt(2, 'l');
array3.setAt(3, 'l');
array3.setAt(4, 'o');
std::cout << "array3 내용 (char 타입, 크기 5):" << std::endl;
for (int i = 0; i < array3.getSize(); i++) {
std::cout << array3.getAt(i);
}
std::cout << std::endl;
return 0;
}
템플릿 매개변수의 기본값을 사용하면 사용자가 모든 템플릿 인수를 명시적으로 지정하지 않아도 됩니다.
'Programming Languages > C++' 카테고리의 다른 글
가변 템플릿(Variadic Templates) (C++11) (0) | 2025.03.28 |
---|---|
비타입 템플릿 매개변수 (0) | 2025.03.28 |
템플릿 (0) | 2025.03.28 |
챕터6. 실습 문제 (0) | 2025.03.28 |
고급 포인터 주제 (0) | 2025.03.28 |