본문 바로가기

Information Technology/C++

[C++] 클래스 템플릿

이 글은 개인의 학습을 목적으로 정리한 글입니다. 이점 참고하고 읽어주세요 ;)


class MyArray
{
private:
	int m_length;
	int* m_data;

public:
	MyArray()
	{
		m_length = 0;
		m_data = nullptr;
	}

	MyArray(int length)
	{
		m_data = new int[length];
		m_length = length;
	}

	~MyArray()
	{
		reset();
	}

	void reset()
	{
		delete[] m_data;
		m_data = nullptr;
		m_length = 0;
	}

	int& operator [](int index)
	{
		assert(index >= 0 && index < m_length);
		return m_data[index];
	}

	int getLength()
	{
		return m_length;
	}

	void print()
	{
		for (int i = 0; i < m_length; ++i)
			std::cout << m_data[i] << " ";
		std::cout << std::endl;
	}
};

여기 간단... 하지는 않지만 클래스 하나를 정의했습니다.

배열에 관한 클래스입니다. 그리고 사용하는 자료형은 int 자료형입니다. 이렇게 클래스를 정의했는데, int 자료형 외에도 float, double, char 등등.. 의 다양한 자료형을 사용하는 클래스도 만들어야 한다고 합니다. 앞선 포스팅에서 다뤘던 함수도 그 크기가 커지면 반복 작업으로 발생하는 효율성의 문제가 생기는데, 클래스는 속된 말로 답도 없습니다.

다행히도 함수 뿐만이 아니라 클래스에도 템플릿template 선언이 가능합니다. 그 방법을 알아보겠습니다.


template<typename T>
class MyArray
{
.
.
.
}

큰 틀은 함수 템플릿과 같습니다. 함수 템플릿에서 했던 것처럼 클래스를 정의하는 바로 윗줄에 template<typename 자료형의 이름으로 사용할 문자>를 선언해줍니다. 이 예제에서는 typename으로 T를 사용합니다.

typename의 자리에는 class를 입력해도 대부분 정상적으로 작동한다고 합니다. 하지만 typename이 조금 더 자주? 그리고 포괄적으로 사용되는 것 같습니다.

template<typename T>
class MyArray
{
private:
	int m_length;
	T* m_data; // T자료형 멤버를 저장할 배열의 이름이자 주소

public:
	MyArray()
	{
		m_length = 0;
		m_data = nullptr;
	}

	MyArray(int length)
	{
		m_data = new T[length]; // T자료형의 멤버를 저장
		m_length = length;
	}

	~MyArray()
	{
		reset();
	}

	void reset()
	{
		delete[] m_data;
		m_data = nullptr;
		m_length = 0;
	}

	T& operator [](int index) // 첨자 연산자를 통해 m_data의 해당 인덱스의 T 자료형 멤버를 출력
	{
		assert(index >= 0 && index < m_length);
		return m_data[index];
	}

	int getLength()
	{
		return m_length;
	}

	void print()
	{
		for (int i = 0; i < m_length; ++i)
			std::cout << m_data[i] << " ";
		std::cout << std::endl;
	}
};

template 선언?을 한 후에는 클래스를 정의하는 바디의 자료형도 바꿔줍니다. 위의 코드 블록에서 각주를 적은 부분이 원래 클래스에서 수정한 부분입니다.

int main()
{
	MyArray<int> my_array(10);

	for (int i = 0; i < my_array.getLength(); ++i)
		my_array[i] = i * 10;

	my_array.print();

	return 0;
}

이제 main함수에서 MyArray 클래스를 사용해보겠습니다. 클래스 템플릿을 사용하는 방법은 함수 템플릿을 사용하는 방법과 다른 점이 하나 있습니다.

MyArray<int> my_array(10);

바로 사용하는 클래스 바로 옆에 사용하려는 자료형을 괄호 안에 입력해야 하는 점입니다. 이 예제에서는 int 형 자료를 사용하기 때문에 MyArray<int> 이렇게 int 자료형을 입력했습니다.


지금부터 설명드릴 내용은 헤더 파일과 관련된 내용입니다.

프로그램을 작성할 때, main.cpp 파일에 모든 클래스와 main함수를 함께 넣어두는 것은 좋지 않습니다. 때문에 main함수에서 사용할 클래스나 함수는 따로 헤더 파일을 만들고 main함수에서 이 헤더파일을 참조하는 방식을 사용합니다.

위에서 정의한 MyArray함수 역시 따로 MyArray.h라는 헤더 파일에 저장을 했고 main.cpp 파일에서 MyArray.h 파일을 참조했습니다.

그런데 사용하는 클래스가 많다 보면 클래스들을 저장한 헤더 파일의 크기도 커지기 마련입니다. 때문에 헤더 파일에 저장한 클래스의 멤버들 중 멤버 함수의 선언 부분만 남겨두고, 함수의 바디는 다시 cpp파일을 만들어서 따로 저장합니다.

template<typename T>
class MyArray
{
.
.
.
	void print();
};

이 코드는 지금 MyArray.h 파일에 저장된 코드이고, 예제로 사용한 클래스 중 print함수를 선언만 남겨두고 함수의 바디는 MyArray.cpp파일에 따로 저장을 했습니다.

#include "MyArray.h"

template<typename T>
void MyArray<T>::print()
{
	for (int i = 0; i < m_length; ++i)
		std::cout << m_data[i] << " ";
	std::cout << std::endl;
}

이게 MyArray.cpp 파일의 코드이고, 역시 MyArray.h 파일을 참조합니다.

#include "MyArray.h"

int main()
{
	MyArray<int> my_array(10); //error!

	for (int i = 0; i < my_array.getLength(); ++i)
		my_array[i] = i * 10;

	my_array.print();

	return 0;
}

이제 MyArray.h를 참조하는 main함수에서 아까와 같이 템플릿 선언을 한 MyArray 클래스를 사용해보려고 하는데,

어라? MyArray 클래스 자료형의 인스턴스를 만드려고 하는데 에러가 발생합니다.

이는 MyArray.h 파일이 MyArray.cpp파일까지 가져오지 못해서, MyArray.h 파일 속에 있는 print함수 선언이 어떤 자료형을 가져와야 할지 모르기 때문이라고 합니다.

이를 해결하는 방법에는 main.cpp 파일에 MyArray.cpp 파일까지 참조하는 방법도 있지만, 이는 프로젝트의 크기가 커질수록 비효율적이고 문제가 발생할 소지도 많기 때문에 그리 추천하는 방법은 아닙니다.

그러하면 이 문제를 어떻게 해결해야 할까요?

#include "MyArray.h"

template<typename T>
void MyArray<T>::print()
{
	for (int i = 0; i < m_length; ++i)
		std::cout << m_data[i] << " ";
	std::cout << std::endl;
}

template class MyArray<char>;
template class MyArray<double>;
.
.
.

바로 MyArray.cpp파일에서 클래스 자체에 자료형을 템플릿으로 설정해주는 방법입니다.

이렇게 main.cpp 파일에서 MyArray 클래스를 통해 사용하기 위해 필요한 자료형들을 입력해주면 main.cpp에서 MyArray.cpp를 참조하지 않아도 무리 없이 MyArray 클래스를 사용할 수 있습니다!

'Information Technology > C++' 카테고리의 다른 글

[C++] 함수 템플릿 특수화  (0) 2019.11.20
[C++] 자료형이 아닌 템플릿 매개변수  (0) 2019.11.20
[C++] 함수 템플릿  (0) 2019.11.19
[C++] 변환 생성자와 explicit  (0) 2019.11.19
[C++] 형변환 오버로딩  (1) 2019.11.17