Menu
Coddy logo textTech

클래스 템플릿

Coddy C++ 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 104개 중 65번째.

함수 템플릿이 타입에 독립적인 함수를 작성할 수 있게 해주는 것처럼, 클래스 템플릿은 타입에 독립적인 클래스를 생성할 수 있게 해줍니다. 이것이 std::vector와 같은 컨테이너가 작동하는 방식입니다. 즉, 구조를 한 번 정의하면 컴파일러가 사용하는 각 타입에 대해 구체적인 버전을 생성합니다.

template <typename T>
class Box {
    T value;
public:
    Box(T v) : value(v) {}
    T getValue() const { return value; }
    void setValue(T v) { value = v; }
};

int main() {
    Box<int> intBox(42);
    Box<std::string> strBox("Hello");
    
    std::cout << intBox.getValue() << std::endl;  // 42
    std::cout << strBox.getValue() << std::endl;  // Hello
}

함수 템플릿과 달리, 클래스 템플릿으로부터 객체를 생성할 때는 꺽쇠 괄호를 사용하여 타입을 명시적으로 지정해야 합니다. 그러면 컴파일러는 해당 특정 타입에 대한 완전한 클래스 정의를 생성합니다.

클래스 템플릿은 여러 개의 타입 매개변수뿐만 아니라 정수와 같은 비타입 매개변수도 가질 수 있습니다:

template <typename T, int Size>
class FixedArray {
    T data[Size];
public:
    T& operator[](int index) { return data[index]; }
    int size() const { return Size; }
};

FixedArray<double, 5> arr;  // 5개의 double형 배열
arr[0] = 3.14;

클래스 외부에서 멤버 함수를 정의할 때, 템플릿 선언을 반복해야 합니다:

template <typename T>
class Container {
    T* data;
public:
    Container();
    ~Container();
};

template <typename T>
Container<T>::Container() : data(nullptr) {}

template <typename T>
Container<T>::~Container() { delete data; }

클래스 템플릿은 C++에서 제네릭 프로그래밍의 기초를 형성하며, 어떤 타입과도 작동하는 재사용 가능한 데이터 구조를 작성할 수 있게 해줍니다.

challenge icon

챌린지

쉬움

클래스 템플릿을 사용하여 어떤 유형의 데이터든 담을 수 있는 유연한 컨테이너인 제네릭 저장 시스템을 구축해 보겠습니다. 템플릿 클래스를 헤더 파일에 구성하고, 메인 프로그램에서 다양한 타입을 사용하여 그 다재다능함을 증명해 보세요.

두 개의 파일을 생성하게 됩니다:

  • Storage.h: 몇 가지 유용한 연산을 수행하며 단일 값을 위한 단순 컨테이너 역할을 하는 Storage라는 클래스 템플릿을 정의합니다.

    Storage 템플릿은 다음을 포함해야 합니다:

    • 저장된 값을 보유하는 private 멤버
    • 초기값을 인자로 받는 생성자
    • 저장된 값을 반환하는 getValue() 메서드
    • 저장된 값을 업데이트하는 setValue() 메서드
    • 값이 T 타입의 기본 생성된 값과 같으면 true를, 그렇지 않으면 false를 반환하는 isEmpty() 메서드

    또한 두 개의 관련 값을 저장하는 두 개의 타입 파라미터를 가진 Pair라는 클래스 템플릿을 생성합니다:

    • 첫 번째와 두 번째 값을 위한 private 멤버 (잠재적으로 서로 다른 타입일 수 있음)
    • 두 값을 모두 초기화하는 생성자
    • 각 값을 검색하는 getFirst()getSecond() 메서드
    • (<first>, <second>) 형식으로 출력하는 display() 메서드
  • main.cpp: 네 개의 입력(각각 별도의 줄에 있음)을 읽습니다:
    1. 정수 값
    2. 새로운 정수 값
    3. 문자열 값
    4. double 값

    다음을 통해 템플릿을 시연하세요:

    1. 첫 번째 정수로 Storage<int>를 생성하고, Int storage: <value>를 출력합니다.
    2. setValue()를 사용하여 두 번째 정수로 업데이트한 후, Updated: <value>를 출력합니다.
    3. 입력받은 문자열로 Storage<std::string>을 생성하고, String storage: <value>를 출력합니다.
    4. 문자열 저장소가 비어 있는지 확인하고 Is empty: <true/false>를 출력합니다 (true 또는 false 출력).
    5. 문자열과 double 값으로 Pair<std::string, double>을 생성한 다음 display()를 호출합니다.
    6. 두 정수 입력값으로 Pair<int, int>를 생성한 다음 display()를 호출합니다.

예를 들어, 입력값이 42, 100, Hello, 3.14인 경우:

Int storage: 42
Updated: 100
String storage: Hello
Is empty: false
(Hello, 3.14)
(42, 100)

동일한 Storage 템플릿이 정수 및 문자열과 어떻게 원활하게 작동하는지, 그리고 Pair가 어떻게 서로 다른 타입을 결합할 수 있는지 확인해 보세요. 컴파일러는 사용하는 각 타입 조합에 대해 별도의 클래스 정의를 생성합니다. 단일 타입 템플릿에는 template <typename T> 구문을 사용하고, 여러 타입 파라미터가 있는 템플릿에는 template <typename T, typename U> 구문을 사용해야 함을 기억하세요.

치트 시트

클래스 템플릿을 사용하면 타입에 독립적인 클래스를 생성할 수 있습니다. 컴파일러는 사용자가 사용하는 각 타입에 대해 특정 버전을 생성합니다.

기본 클래스 템플릿

template <typename T>
class Box {
    T value;
public:
    Box(T v) : value(v) {}
    T getValue() const { return value; }
    void setValue(T v) { value = v; }
};

클래스 템플릿으로 객체를 생성할 때는 꺾쇠괄호를 사용하여 타입을 명시적으로 지정해야 합니다:

Box<int> intBox(42);
Box<std::string> strBox("Hello");

여러 개의 타입 매개변수

클래스 템플릿은 여러 개의 타입 매개변수를 가질 수 있습니다:

template <typename T, typename U>
class Pair {
    T first;
    U second;
public:
    Pair(T f, U s) : first(f), second(s) {}
};

비타입 매개변수

템플릿은 정수와 같은 비타입 매개변수도 받을 수 있습니다:

template <typename T, int Size>
class FixedArray {
    T data[Size];
public:
    int size() const { return Size; }
};

FixedArray<double, 5> arr;  // Array of 5 doubles

클래스 외부에서 멤버 함수 정의하기

클래스 외부에서 멤버 함수를 정의할 때는 템플릿 선언을 반복해야 합니다:

template <typename T>
class Container {
    T* data;
public:
    Container();
    ~Container();
};

template <typename T>
Container<T>::Container() : data(nullptr) {}

template <typename T>
Container<T>::~Container() { delete data; }

직접 해보기

#include <iostream>
#include <string>
#include "Storage.h"

using namespace std;

int main() {
    // 입력 읽기
    int intValue1;
    int intValue2;
    string strValue;
    double doubleValue;
    
    cin >> intValue1;
    cin >> intValue2;
    cin >> strValue;
    cin >> doubleValue;
    
    // TODO: 첫 번째 정수로 Storage<int>를 생성하고 출력: Int storage: <value>
    
    // TODO: setValue()를 사용하여 두 번째 정수로 업데이트하고 출력: Updated: <value>
    
    // TODO: 문자열 입력으로 Storage<std::string>을 생성하고 출력: String storage: <value>
    
    // TODO: 문자열 저장소가 비어 있는지 확인하고 출력: Is empty: true/false
    
    // TODO: 문자열과 double로 Pair<std::string, double>을 생성하고 display() 호출
    
    // TODO: 두 정수로 Pair<int, int>를 생성하고 display() 호출
    
    return 0;
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨