template

킴스코딩클럽·2022년 12월 9일
1

CS기초 시리즈

목록 보기
62/71

타입을 일반화하는 방식

타입별로 서로 다른 함수를 재작성할 필요가 없어짐

void Sort(T scores[])
{
	//원소의 타입을 T라고 하자
}

template 문법

OOP에서는 INT 같은 TYPE을 CLASS TYPE으로 객체화하기 때문에 TYPENAME만 써도 됨

template <typename T1, typename T2, typename T3 ....>
template <class T1, class T2, class T3 ....>

void Sort(T val, T2 val2, T3 val3...)
{
	T x;
    T2 y;
}

template 코딩

#include <iostream>

void Sort(int input[], int size)
{
	for ( int i = 0; i < size-1; i++ )
	{
		for ( int j = i+1; j < size; j++ )
		{
			if ( input[i] > input[j] )
			{
				int temp = input[i];
				input[i] = input[j];
				input[j] = temp;
			}
		}
	}
}

void Sort(float input[], int size)
{
	for ( int i = 0; i < size - 1; i++ )
	{
		for ( int j = i + 1; j < size; j++ )
		{
			if ( input[i] > input[j] )
			{
				float temp = input[i];
				input[i] = input[j];
				input[j] = temp;
			}
		}
	}
}

void Sort(bool input[], int size)
{
	for ( int i = 0; i < size - 1; i++ )
	{
		for ( int j = i + 1; j < size; j++ )
		{
			if ( input[i] > input[j] )
			{
				bool temp = input[i];
				input[i] = input[j];
				input[j] = temp;
			}
		}
	}
}

class Student
{
public:
	int scores;


};
//클래스에 대한 sort
void Sort(Student input[], int size)
{
	for ( int i = 0; i < size - 1; i++ )
	{
		for ( int j = i + 1; j < size; j++ )
		{
			if ( input[i].scores > input[j].scores )
			{
				Student temp = input[i];
				input[i] = input[j];
				input[j] = temp;
			}
		}
	}
}

//무슨타입이든 하나의 정렬함수로 모든 타입이 가능하도록
//힌트 : 배열은 포인터
//포인터중 타입과 상관없는것 : void

enum Type
{
	INT,
	FLOAT,
	BOOL,
	DOUBLE,
	CHAR,
};
void Sort(void *input, int size,Type t)
{
	switch ( t )
	{
		case INT:
			break;
		case FLOAT:
			break;
		case BOOL:
			break;
		case DOUBLE:
			break;
		case CHAR:
			break;
		default:
			break;
	}
}

//이런 방법을 쉽게 하는 것
//템플릿
//타입을 일반화(Generic Programming)


template<typename T>

void Sort(T input[], int size)
{
	for ( int i = 0; i < size - 1; i++ )
	{
		for ( int j = i + 1; j < size; j++ )
		{
			if ( input[i] > input[j] )
			{
				T temp = input[i];
				input[i] = input[j];
				input[j] = temp;
			}
		}
	}
}
//일반화시킨 정렬

int main()
{
	int scores[] {10,20,30,40,50};

	Sort(scores, 5);

	for ( int i = 0; i < 5; i++ )
	{
		std::cout << scores[i] << std::endl;
	}

	float scores2[] {1.1f,2.2f,3.3f,10.0f,5.0f};
	//오버로딩으로

	Sort(scores2, 5);

	char scores[] {10,20,30,40,50};	//이렇게 모든 타입으로 가능
}

template argument deduction

컴파일러가 타입을 명시하지 않아도 자동으로 찾아줌

template <typename MyType1>
//타입의 이반화 Genaralization
MyType1 Function(MyType1 val1,MyType1 val2)
{
	MyType1 result;

	result = val1 + val2;
	return result;
}

class Students
{
public:
	int scores;

	int operator+()
	{
		return;
		//students사이에 연산지 제공되면 가능함 
		//하지만 없으면 에러
		//template과 연산자 오버로딩이 조화가 잘됨

	}
};

int main()
{
	//표기법

	//특수화
	std::cout << Function<int>(3, 4) << std::endl;	
	//int를 mytype이라고 하자고 명시해줌


	//컴파일러가 발전하면서 template argument deduction
	//매개변수 추론
	Function(3, 4);
	//int임을 알수있음=>추론 가능함=>생략가능
	//템플릿임을 알려주기 위해서 생략안하기도 함
	//어떻게 알 수 있나??
	//컴파일러가 프로그래머가 수동으로 타입을 변환하듯이 컴파일함
	//코드를 복사해서 붙여넣기하는 작업을 컴파일러가 대신하는 작업

	Students a, b;
	a.scores = 10;
	b.scores = 20;
}

template class

template <typename T>
class Myclass
{
	T member;
    T function(T val);
};

주의사항

  1. 자동 아니고 AI 아니고 복사 붙여넣기임
    이 템플릿을 사용할 수록 코드의 양이 늘어남 -> 최적화 문제
  2. 템플릿은 선언과 정의가 같은 파일에 있어야 함
    -> 템플릿은 실제로 존재하는 타입이 아니고 특수화를 할 때 존재하게 되는 것 그래서 정의가 같이 있어야함
    -> 타입으로 특수화를 해야함
    -> 컴파일러가 복붙을 하기 때문에 생기는 문제
template <typename T>
class MyClass
{
	T mValue;
public:
	void F(T arg);
};
void MyClass<T> :: F(T arg)
{
}
선언과 정의를 분리하는 방법
같은 곳에 있어야함
  1. #include "MyClass.hpp"
    template의 정의를 hpp에 옮길 수 있음
    선언과 정의를 무조건 분리해야하는 사람을 위한 기능
    *.h *.hpp *.cpp

사소한 팁

가상함수 사용법

실수할 확률이 적어짐
virtual쓸때 자식에 override쓰기

class Parent
{
public:
	virtual void F();

};

class child : public Parent
{
public:
	void F() override;
	//부모에서 virtual 자식에서 override를 쌍으로 쓰는 것을 기억하기
};

explicit 키워드 사용

#include<iostream>

class MyClass
{
public:
	int mInt;
	MyClass()
	{
		std::cout << "나일까?" << std::endl;
	}

	explicit MyClass(int val):mInt {val}
	{
		std::cout << "불렸나?" << std::endl;
		//생성자가 없이 가능한가??
		//생성자를 제공하면 기본생성자가 없음
		//그러면 생성자를 만든 것 아닐까>
		//생성자를 없애면 main안 코드가 불가능(생성자가 없어서)
	}
};

int main()
{
	MyClass c = MyClass(1);			//생성자가 없으면 불가능 MyClass c = 1;과 같음
	//MyClass c = 1;				생성자가 없으면 불가능(명시적 생성자가 있으면 에러)
	
	//위 초기화 방식을 막는 것이 explicit 키워드 
	//
	
	MyClass c {1};				
	//멤버를 바꾸는 초기화 방식 = 생성자 없어도 불가능함
	//표기법상으로는 어떤 것인지 애매함
	//구분하기 위해서 명시적 생성자라는 기능이 존재함
	MyClass c3(3);
	

}
profile
공부 기록용

0개의 댓글