Generic Programming

March 02, 2020

Generic Programming이란?

제네릭(Generic)은 데이터 형식에 의존하지 않고, 하나의 값이 여러 다른 데이터 타입들을 가질 수 있는 기술에 중점을 두어 재사용성을 높일 수 있는 프로그래밍 방식이다.

int max(int a, int b){
	return (a > b) ? a : b;
}

double max(double a, double b){
	return (a > b) ? a : b;
}

__int64 max(__int64 a, __int64 b){
	return (a > b) ? a : b;
}

........

위의 예제를 보면 내부 로직이 같은 함수들이 자료형의 차이로 인해 수 많이 Overloading 하고 있다.
만약, 내부 로직이 변경이 된다면 저 모든 함수들의 로직을 함께 바꾸어 주어야 한다.

이러한 것을 C++에서는 template를 활용하여 해결한다.

template<typename T>{
T max(T a, T b){
	return (a>b) ? a : b;
}

여기서 T는 다양한 자료형으로 mapping될 수 있으며, 이를 generic화 했다고 한다.

개선하기

위의 예제는 3가지 단계를 거쳐서 개선할 수 있다.

// 1단계
// - 참조자를 이용하여 속도를 높인다.
// - const를 사용하여 값의 변경을 막는다.
template <typename T>
const T& max(const T& a, const T& b){
	return (a > b) ? a : b;
}
// 2단계
// 함수의 파라미터가 서로 다른 것이 들어 온다면?
template <typename T1, typename T2>
const T1& max(const T1& a, const T2& b>{
	return (a > b) ? a : b;
}
// 3단계 - Specialization
// 위의 코드 같은 경우 T2로 들어오는 Data type이 더 크다면
// return type 불일치로 error가 발생한다.
// 이 경우 예외를 처리할 수 있다.
template <typename T1, typename T2>
const T1& max(const T1& a, const T2& b>{
	return (a > b) ? a : b;
}

template <>
const double& max(const int& a, const double& b){
	return (a > b) ? a : b;
}

Class Template

함수만 아니라 클래스의 경우에도 tempalte 적용이 가능하다.

아래 두 가지 예시를 첨부한다.

// 예시 1 - Stack
template <typename T, int SIZE>
class Stack
{
private:
	T m_aData[SIZE];
	int m_Count;
	
public:
	Stack()
	{
		Clear();
	}

	// 초기화 한다.
	void Clear()
	{
		m_Count = 0;
	}

	// 스택에 저장된 개수
	int Count()
	{
		return m_Count;
	}

	// 저장된 데이터가 없는가?
	bool IsEmpty()
	{
		return (0 == m_Count) ? true : false;
	}

	// 데이터를 저장한다.
	bool push( T data )
	{
		// 저장 할수 있는 개수를 넘는지 조사한다.
		if( m_Count >= MAX_COUNT )
		{
			return false;
		}
		// 저장 후 개수를 하나 늘린다.
		m_aData[ m_Count ] = data;
		++m_Count;
		
		return true;
	}

	T pop()
	{
		// 저장된 것이 없다면 0을 반환한다.
		if( m_Count < 1 )
		{
			return 0;
		}
		// 개수를 하나 감소 후 반환한다.
		--m_Count;
		return m_aData[ m_Count ];
	}
}
template <typename T>
class MySingleton{
private:
	static T& _Singleton;
	
	MySingletone() {}
	virtual ~MySingletone() {}

public:
	// 이 멤버를 통해서만 생성이 가능하다.
	static T* GetSingleton()
	{
		// 아직 생성이 되어 있지 않으면 생성한다.
		if( NULL == _Singleton ) {
			_Singleton = new T;
		}
		return ( _Singleton );
	}

	static void Release()
	{
		delete _Singleton;
		_Singleton = NULL;
	}
}


class MyObject : public MySingleton<MyObject>
{
public:
	MyObject() : _nValue(10) {}
	void SetValue( int Value ) { _nValue = Value;}
	int GetValue() { return _nValue; }

private :
	int _nValue;
};

songmk 🙁