본문 바로가기
언어/C++

[C++ STL] 1-2. 템플릿 - 클래스 템플릿(class template)

by 민-Zero 2020. 1. 12.

공부 내용을 정리하는 목적 이므로 참고용으로만 읽어 주시기 바랍니다.

틀린 부분에 대한 지적은 감사합니다.

1. 클래스 템플릿(class template)

함수 템플릿이 기능만 정의되고 타입이 정의되지 않은 함수의 일반화였다. 클래스 템플릿(class template)도 마찬가지로 클래스의 일반화이다. 클래스 템플릿을 정의하면 타입에 따라 클래스를 생성할 수 있다.

함수 템플릿과 다른 점이 있다 함수의 경우 명시적으로 템플릿 인수를 작성하지 않아도 동작했지만 클래스 템플릿은 무조건 템플릿 인수를 명시해 주어야 한다.

이유는 클래스의 객체를 생성하는 과정에 있다. 인스턴스화를 진행할 때 해당 객체에 대한 메모리를 할당하고 생성자를 호출하게 된다. 하지만 클래스 템플릿의 데이터 타입이 결정되려면 생성자가 호출되어야 한다. 따라서 명시적으로 템플릿 인수를 작성하지 않을 경우 어떤 타입에 대한 메모리를 할당해야 하는지 모르기 때문에 객체를 생성할 수 없기 때문에 객체 생성 시 템플릿 인수를 명시해 주어야 한다.

 

법)

template<typename 타입이름1, typename 타입이름2, ...>

class 클래스명{

    클래스 멤버;

};

 

간단한 예시를 통해 클래스 템플릿을 확인하자

멤버 변수 val과 멤버 함수 GetVal, PrintInfo를 가지는 간단한 클래스 템플릿을 생성했다. 주의할 점은 멤버 함수를 클래스 외부에서 정의할 경우 임의의 타입 T를 정의해 주어야 하기 때문에 template<typenae T>를 적어 주어야 하며 범위 연산자를 통해 어떤 클래스의 멤버 함수인지 표현해 줄 때도 T Test<T>::GetVal() 로 클래스에 명시해줘야 한다. typename T는 임의의 데이터 타입 T를 사용한다 라는 뜻이므로 T 대신 다른 이름을 사용해도 된다.

객체 생성 시 명시해준 템플릿 인수에 따라 타입이 적용된 것을 확인할 수 있다.

 

2. 클래스 템플릿 활용

클래스 템플릿을 상속하여 사용할 수 있다. 앞서 생성한 Test클래스를 상속받는 Test2라는 클래스를 생성해보자.

상속 방법은 일반적인 클래스를 상속하는 방법과 똑같다. 상속하는 부모 클래스 또한 임의의 클래스로 정하고 싶다면 2개의 템플릿 인수를 사용하면 된다. 부모 클래스를 작성할 때 템플릿 인수를 명시하는 것을 빼먹으면 에러가 발생한다.

부모 클래스의 타입을 정하여 상속하고 싶다면 상속할 때 class Test2 : public Test<int>처럼 템플릿 인수를 정해 상속시켜주면 된다.

 

클래스를 중첩하여 정의하는 중첩 클래스 템플릿이 존재한다. 클래스 내부에서 정의된 템플릿 클래스를 중첩 클래스 템플릿이라고 한다.

이처럼 클래스 템플릿 내부에 또 클래스 템플릿을 사용할 수도 있지만 데이터 타입이 정해진 일반적인 클래스도 사용 가능하다. 이와 같은 중첩 클래스 템플릿은 STL의 이터레이터가 대표적으로 사용하고 있다.

 

템플릿 인수의 디폴트 값을 설정할 수 있다.

템플릿 인수 T에 int값을 디폴트 값으로 선언하면 객체 생성 시 디폴트 인수를 전달하지 않는다면 자동으로 int타입에 대해 동작한다.

 

3. 클래스 템플릿 특수화(specialization)

클래스 템플릿 또한 함수 템플릿과 마찬가지로 특정 타입에 대한 동작을 정의할 수 있다. 객체 생성 시 전달된 템플릿 인수에 부합하는 특수화된 정의를 발견하면 해당 정의를 사용하게 된다.

 

문법)

template<>

class 클래스명<타입>{

    클래스 멤버;

};

 

템플릿 인수가 string 타입일 경우 다른 동작을 수행하도록 특수화를 진행하였다.

따라서 템플릿 인수로 string타입이 전달될 경우 기존의 템플릿 클래스에 정의되어있는 멤버 함수와는 다른 동작을 수행하게 된다.

 

템플릿 인수가 2개 이상일 경우 인수의 일부만 특수화시키는 부분 인수화라는것이 존재한다.

 

문법)

template<typename T>

class 클래스명<T, 특정타입>{

    클래스 멤버;

};

 

템플릿 인수 T1, T2를 가지는 클래스 템플릿을 T2에 string이 들어올 때 특수화를 시켰다. T1에 대한 특수화는 진행하지 않았으므로 특수화 템플릿에서 그대로 템플릿 인수를 통해 임의의 타입에 대해 작성하면 된다. 여기서 T1에 대한 것 까지 특수화를 시키면 앞에서 한 특수화가 되어버린다.

두 번째 템플릿 인수가 string일 때만 특수화를 진행하였으므로 첫 번째 템플릿 인수가 무엇이든 두 번째 템플릿 인수만 string타입이 들어온다면 특수화시킨 동작을 진행하게 된다.

댓글