티스토리 뷰

Programming/C++

C++ - 타입 캐스팅

글그리 2019. 3. 4. 15:26

개요


C++타입의 형변환에 대해 알아보자






static cast


C 타입 캐스팅과 거의 모든면에서 동일하다. 컴파일 타임에 형변환을 감지하고 불가능하다고 판단되면 컴파일 에러를 발생시킨다. 따라서 클래스의 선언이 아래와 같을 때 주석으로 나눈 두 코드는 같은 동작을 한다.


int main() {

   //~ Begin C Type casting

   char CTypeChar = 'a';

   int CTypeInt = CTypeChar;

   //~ End C Type casting

   

   //~ Begin C++ Type casting

   char CppTypeChar = 'a';

   int CppTypeInt = static_cast<int>(CppTypeChar);

   //~ End C++ Type casting

   

   return 0;

}


다만 C 타입 캐스팅과 다른점은 상속관계에 있는 클래스의 포인터형 변환을 허용한다는 점이다. 따라서 클래스 구조가 아래와 같을 때 main함수의 두 코드가 컴파일시점에 에러를 발생하는 경우가 다르다.


class Parent {

public:

   virtual ~Parent();

   virtual void Print();

};

 

Parent::~Parent() {}

void Parent::Print() { std::cout << "I’m Parent" << std::endl; }

 

 

class Driven : public Parent {

public:

   void Print() override;

};

 

void Driven::Print() { std::cout << "I’m Driven" << std::endl; }

 

class Unknown {

public:

   virtual ~Unknown();

   

   void Print();

 

};

 

Unknown::~Unknown() {}

 

void Unknown::Print() { std::cout << "Unknown class" << std::endl; }

 

int main() {

   //~ Begin C Type casting

   Parent* CTypePerent = new Driven();

   Driven* CTypeDriven = CTypeParent;    // compile error

   Unknown* CTypeUnknown = new Unknown();

   CTypeDriven = CTypeUnknown; // compile error

   //~ End C-Type casting

   

   //~ Begin C++ Type casting

   Parent* CppTypeParent = new Driven();

   Driven* CppTypeDriven = static_cast<Driven*>(CppTypeParent);

   Unknown* CppTypeUnknown = new Unknown();

   CppTypeDriven = static_cast<Driven*>(CppTypeUnknown);   // compile error

   //~ End C++ Type casting

   

   return 0;

}




dynamic cast


캐스팅이 유효한지 컴파일 타임에 검사하지 않고 런타임에 검사하도록 하는 문법. 실행도중 캐스팅이 유효한지 검사하며 불가능할 경우 NULL을 반환하여 프로그래머가 처리할 수 있도록 한다.

클래스 구조가 위와 동일하다고 할 때 아래 코드는 컴파일은 되지만 캐스팅에 실패하여 “cast fail”을 출력한다.


int main() {

   Driven* CppTypeDriven;

   Unknown* CppTypeUnknown = new Unknown();

   CppTypeDriven = dynamic_cast<Driven*>(CppTypeUnknown);

   

   if(CppTypeDriven != nullptr) {

       CppTypeDriven->Print();

   }

   else {

       std::cout << "cast fail" << std::endl;

   }

   

   return 0;

}


dynamic_cast를 사용하면 상속관계에 있는 클래스의 포인터끼리 형변환이 가능하지만 불가능한 경우에는 NULL을 반환한다.


int main() {

   Parent* ParentHasParent = new Parent();

   Parent* ParnetHasDriven = new Driven();

   

   //~ Begin dynamic cast fail

   Driven* CastedPointer = dynamic_cast<Driven*>(ParentHasParent);

   if(CastedPointer){

       std::cout << "cast success" << std::endl;

   }

   else {

       std::cout << "cast fail" << std::endl;

   }

   //~ End dynamic cast fail

   

   //~ Begin dynamic cast success

   CastedPointer = dynamic_cast<Driven*>(ParnetHasDriven);

   if(CastedPointer){

       std::cout << "cast success" << std::endl;

   }

   else {

       std::cout << "cast fail" << std::endl;

   }

   //~ End dynamic cast success

   

   return 0;

}




reinterpret cast


강제로 형변환을 수행한다. 정수형을 포인터형으로, 전혀다른 클래스의 포인터로 변환할 수 있지만 논리적으로 불가능한경우 런타임에 에러가 발생할 수 있기 때문에 조심해서 사용해야한다. const의 형변환은 수행할 수 없다.

강제로 형 변환을 수행하기때문에 아래 코드는 컴파일이 된다.

int main() {

   Parent* p = new Parent();

   Unknown* u = reinterpret_cast<Unknown*>(p);

   

   return 0;

}




const cast


포인터에 const 속성을 부여하거나 제거할 때 사용한다. 아래처럼 상수성을 제거하여 사용할 수 있다.


int main() {

   int value = 10;

   int value2 = 20;

   const int* a = &value;

   int* b = const_cast<int*>(a);

   *b = 15;

   

   std::cout << *b << std::endl;

}






마치며


C++코드를 짜면서 대충 쓰고있긴 했지만 이번기회에 정확히 짚고넘어가자는 생각으로 포스팅을 쓰기시작했다. 그런데 공부를 하고나서도 static_cast랑 dynamic_cast 말고는 딱히 어디에 써야할지 감이 안잡힌다.



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

C++ Expert | 상황별 const의 의미  (0) 2020.09.06
C++ - 스마트 포인터(smart pointer)  (2) 2019.03.29
C++ - 클래스 관계 용어 정리  (0) 2018.03.02
C++ - 메모리 해제  (0) 2017.12.30
C++ - 메모리 생성  (0) 2017.12.30
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함