Game Programming/게임 프로그래밍 C++

[C++] 형변환과 템플릿

Doanie 2022. 9. 12. 17:46

[C++] 형변환과 템플릿


형변환

데이터를 다른 데이터 형으로 바꾸는 과정이다.

int num = 250;
float fNum1 = num/100; //fNum1 == 2.0f
float fNum2 = (float)num/100; //fNum2 = 2.5f 명시적 형변환
float fNum3 = num; //묵시적 형변환. 컴파일러가 형을 변환해준다.

형변환을 해야하는 경우

1. 다른 코드 섹션의 인터페이스가 특정한 형을 요구할 때

2. 개체의 다형적 이용

C++ 스타일 형변환

▷ static_cast

정적 형변환, 컴파일 타임에 형변환이 가능한지 검사한다.

class A {};
class B : public A {};
class C {};

A* a = new A();
B* b = static_cast<B*>(a); //형변환 가능
C* c = static_cast<C*>(a); //형변환 불가능

1. C형의 형변환이 제한된 버전으로 컴파일러에게 두개의 다른 데이터형 변환을 요구한다.

2. 정확도의 손실이 있을지라도 내장 데이터형 같은 변환을 수행한다.

3. 연관된 포인터형 사이에서만 변환을 수행한다.

4. 상수를 바꾸는데 사용할 수 없다.

즉, 다른 형변환들과는 다르게 기본 자료형의 형변환을 허용한다.

 

 const_cast

다른 자료형으로 변환이 불가능하며 적용된 식의 항상성을 변경가능한 형변환이다.

const char* text = "world";
char* cText = const_cast<char*>(text);

A* a1 = new A();
const A* a2 = a1;
A* a3 = const_cast<A*>(a2);

이런식의 코드 디자인을 사용하게 된다면 다시 생각해보는 것이 좋을것 같다.

 

 reinterpret_cast

reinterpter : 재해석하다.

일반적으로 허용하지 않는 형변환을 강제적으로 형변환할때 사용한다.

class A {
private:
	int index;
};

class B {
private:
	int index;
};
//...
int main()
{
	A* a = new A();
	B* b = new B();
    
	b = static_cast<B*>(a); 	//컴파일 에러
	b = reinterpret_cast<B*>(a);//형변환 가능
    
	return 0;
}

1. 어떤 내장형 데이터라도 다른형으로 형변환이 가능하다.

2. 어떤 포인터형이라도 다른 포인터형으로 변환이 가능하다.

3. 안정성, 항상성에 관계없이 형변환을 수행한다.

4. 연산자의 결과는 컴파일러에 따라 달라지며, 형변환하는 개체의 메모리 레이아웃에 영향을 받는다.

유용하게 사용할수도 있지만 안정성이 매우 떨어지기 때문에 사용을 자제하도록하자!

 

 dynamic_cast

동적 형변환, static_cast와는 달리 런터임시에 형변환을 검사하여 안전하게 처리한다.

class Base {
public:
	//...
};

class A : public Base {
public:
 	//...
};

class B : public Base {
public:
	//...
};
//...
int main()
{
	Base* b = new B();
    
	A* a1 = dynamic_cast<A>(b); //NULL
	B* a2 = dynamic_cast<B>(b); //형변환 가능
    
	return 0;
}

1. 변환이 가능한지 런타임에서 판단하여 내장 데이터형 제외한 포인터나 참조에 이용한다.

2. static_cast 과는 다르게 두 포인터가 상속 트리인지 확인하지 않는다.

3. 변환 가능 시 다중 상속을 처리하기 위한 오프셋 계산까지 마친 새로운 포인터를 리턴한다.

4. 불가능 시에는 NULL 포인터를 리턴한다.

5. 컴파일러의 RTTI세팅을 켜둬야한다.

RTTI(RunTime Type Information) : 실시간 타입 정보. 런타임의 타입 정보를 알아내는 것이다.

 

용도에 따른 4가지 형변환들이 있으며 상황에 맞게 static, dynamic을 쓰는게 좋을거 같다.


템플릿 (Template)

특정한 클래스나 데이터형에 얽매이지 않고 코드를 작성할 수 있게한다. 템플릿 이용을 원할 때 함께 사용하고자 하는 특정 클래스를 위한 인스턴화 과정을 거친다.

인스턴화 : 추상적인 것을 구체적으로하는 것이다.

즉, 클래스나 함수를 개별적으로 다시 작성하지 않아도 여러 데이터형으로 사용할 수 있도록 만들어놓은 틀이다.

 

템플릿의 장점

1. 코드가 다른 장소로 복제가 되지않는다.

2. 데이터형의 안정성을 보장한다.

3. 공용 기반 클래스에서 상속을 필요로 하지 않는다. 

템플릿의 단점

1. 읽기 쉽지 않고 디버깅이 어려워 복잡성을 가질 수 있다.

2. 구현에 필요한 모든 헤더 파일을 가지고 있어 클래스 서로의 의존성이 커진다.

3. 코드가 길어질 수 있다.

클래스 템플릿

class Circle {
public:
	Circle(float pRadius) { radius = pRadius }
  	float GetRadius() { return radius; }
  	float GetDiameter() { return 2 * 3.14f * radius; }
  	float GetArea() { return 3.14f * radius * radius; }
    
  	float radius;
};

↓  템플릿화 ↓

template<class T>
class Circle {
public:
	Circle(T pRadius) { radius = pRadius }
  	T GetRadius() { return radius; }
  	T GetDiameter() { return 2 * 3.14f * radius; }
  	T GetArea() { return 3.14f * radius * radius; }
    
  	T radius;
};
//...
int main()
{
	Circle<int> c1(1); 		//int형 반지름을 가진 원 생성
    Circle<float> c2(1.0f); //float형 반지름을 가진 원 생성
	return 0;
}

함수 템플릿

template<class T>
void swap(T& a, T& b)
{
	T tmp(a);
  	a = b;
  	b = tmp;
}
//...
int main()
{
	//int
  	int a1 = 5;
  	int b1 = 0;
  	swap(a1, b1); //a1 == 0, b1 == 5
    
  	//float
  	float a2 = 1.0f;
 	float b2 = -1.0f;
  	swap(a2, b2); //a2 == -1.0f, b2 == 1.0f
	return 0;
}

템플릿 특화

완전/부분 템플릿 특화가 있으며, 특정 클래스나 일부 클래스를 위한 약간의 커스텀화를 가능하게 하는 것이다.

완전 템플릿 특화 : 특정 클래스를 위한 커스텀 버전의 템플릿을 제공할 수 있게 해준다.

부분 템플릿 특화 : 어떤 형의 포인터라도 처리할 수 있게 해준다.


형변환과 템플릿에 관하여 알아보았다. 각각 사용의 용도가 정해져있고 용도 외에 오남했을 경우에 치명적인 에러 및 속도를 저하할 수 있다는 사실 또한 알수 있었다.

'Game Programming > 게임 프로그래밍 C++' 카테고리의 다른 글

[C++] 순차 컨테이너와 벡터  (0) 2022.09.16
[C++] STL  (0) 2022.09.16
[C++] 메모리 할당  (0) 2022.09.12
[C++] 포인터,상수, 참조  (0) 2022.09.12
[C++] 클래스와 상속  (0) 2022.09.11