ProgrammingLang/c++

[C++ 개발자되기] 9. type casting (cast operator)

jinkwon.kim 2019. 11. 15. 02:14
728x90
반응형

>>[C++ 관련 모든 글 보기]

1. Type Casting이란?

  변수의 type을 강제로 다른 type으로 변경하는 것을 말합니다. 

 

2. 왜 필요 한가?

  C 나 C++ 변수의 type을 변경 해서 처리하는 경우가 비번 하게 발생합니다.

예를 들어 외부 library사용시 인자로 넘길 변수가 char인데 외부 library가 unsigned char를 사용할 경우 개발자는 char type을 unsigned char로 변경해서 넘겨주어야 Compile Error가 이 발생하지 않습니다

<코드>

 #include <iostream>
 
 int PrintHello(unsigned char *str)
 {                                 
     std::cout<< str << std::endl; 
 }
 
 
 int main() 
 {
     char str[20] = "hello world";
     PrintHello(str);  // Error,  type casting 필요
     // PrintHello(reinterpret_cast<unsigned char*>(str)); // OK
     
     return 0;
 }

<컴파 일시 에러>

[ 44%] Building CXX object CMakeFiles/hello.dir/hello.cpp.o
/root/cpp_test/hello.cpp: In function ‘int main()’:
/root/cpp_test/hello.cpp:12:19: error: invalid conversion from ‘char*’ to ‘unsigned char*’ [-fpermissive]
     PrintHello(str);
                   ^
/root/cpp_test/hello.cpp:3:5: error:   initializing argument 1 of ‘int PrintHello(unsigned char*)’ [-fpermissive]
 int PrintHello(unsigned char *str) 
     ^
make[2]: *** [CMakeFiles/hello.dir/hello.cpp.o] 오류 1
make[1]: *** [CMakeFiles/hello.dir/all] 오류 2

 

3. type casting의 종류

type casting 종류 Tree

4. type casting 별 사용법

  1) 묵시적 형 변환

    (1)  지원 범위

      - C와 C++ 모두 지원합니다. 

    (2) 사용법

      - 컴파일 시 묵시적으로 왼쪽 변수의 type으로 형이 변환됩니다. 개발자가 할 일이 없습니다.

    (3) 예제

#include <iostream>

int main()
{
    float a = 3.14;
    int b;

    b = a; // 왼족 변수(b) type(int)로 우측 변수(a)의 type(float)이 int형으로 묵시적 변환 방생

    std::cout << b << std::endl;
}

// 실행 결과 
3

 

 

  2) 명시적 형 변환

    (1)  지원 범위

      - C와 C++ 모두 지원 합니다. 

    (2) 사용법

      - 개발자가 변환환 type을 명시해 줍니다.

    (3) 예제

#include <iostream>

int main()
{
    float a = 3.14;
    int b;

    b = (int)a; // 왼족 변수(b) type(int)로 우측 변수(a)의 type(float)이 int형으로 명시적 변환 방생

    std::cout << b << std::endl;
}

    (3) 언제 사용 하는가?

      <대표 Case 1>

        - 함수의 인자와 매개변수의 type이 다를 경우 사용

 #include <iostream>
 
 int PrintHello(unsigned char *str)
 {                                 
     std::cout<< str << std::endl; 
 }
 
 
 int main() 
 {
     char str[20] = "hello world";
     
     PrintHello((unsigned char*)str); // 명시적 type casting 사용
     
     return 0;
 }

      <대표 Case 2>

        - void pointer를 사용하여 인자를 넘긴 후 함수에서 다른 type으로 casting 하여 사용할 때

 

  3) static_cast

    (1)  지원 범위

      - C++ 만 지원합니다. 

    (2) 사용법

      - static_cast <변환할 타입>(변환 대상)

    (3) 사용 시기

      - 논리적으로 변경 가능한 경우에만 변경을 허용합니다.

번호 사용 시기 설명 가능 여부
1 실수를 정수로, 정수를 실수로 변환 가능
2 부모 클래스 포인터가 부모 클래스를 가리키는 것은 가능 가능
3 자식 클래스 포인터가 자식 클래스를 가리키는 것도 가능 가능
4 부모 클래스 포인터가 자식 클래스를 가리키는 것도 가능 가능
5 자식 클래스 포인터가 부모 클래스를 가리키는 것도 가능 가능
6 포인터 타입을 정수 타입 등으로 변환 불 가능

    (4) Test Code

#include <iostream>

class Parent
{
public:
    void say()
    {
        std::cout << "parent say" << std::endl;
    }
};

class Child : public Parent
{
public:
    void say()
    {
        std::cout << "Child say" << std::endl;
    }
};


int main()
{
    Parent p_instance;
    Parent* ptr_p_instance;
    Child c_instance;
    Child* ptr_c_instance;
    float b;  // 실수 
    int a;    // 정수
    
    // 1번, 실수를 정수로, 정수를 실수로 변환
    b = 10.111;
    a = static_cast<int>(b);
    std::cout << a << std::endl;
    
    // 1번, 정수를 실수로 변환
    b = static_cast<float>(a);
    std::cout << b << std::endl;
    
    // 3번, 자식 클래스 포인터가 자식 클래스를 가리키는 것도 가능
    c_instance = static_cast<Child>(c_instance);
    c_instance.say();
    
    // 4번, 부모 클래스 포인터가 자식 클래스를 가리키는 것도 가능
    ptr_p_instance = static_cast<Child*>(&c_instance);
    ptr_p_instance->say();
    
    // 5번, 자식 클래스 포인터가 부모 클래스를 가리키는 것도 가능
    ptr_c_instance = static_cast<Child*>(&p_instance);
    ptr_c_instance->say();
    

    return 0;
}   

 

  4) const_cast

    (1)  지원 범위

      - C++ 만 지원합니다. 

    (2) 사용법

      - const_cast <변환할 타입>(변환 대상)

    (3) 사용 시기

      - 포인터 및 참조형에서만 사용 가능하며, 상수 속성(const) 및 volatile 제거할 때 사용합니다.

    (4) Test Code

#include <iostream>

int main()
{
    // 1번, pointer 변수에 Const 지정자를 제거하는 예제
    const int *const_int_ptr = new int(10);
    int *int_ptr;

    std::cout << *const_int_ptr << std::endl;

    int_ptr = const_cast<int*>(const_int_ptr);  // const_int_ptr의 const 지정자를 잠시 제거
    *int_ptr = 20;  // const_int_ptr 의 값을 변경

    std::cout << *const_int_ptr << std::endl;

    return 0;
}

 

  5) reinterpret_cast

    (1)  지원 범위

      - C++ 만 지원합니다. 

    (2) 사용법

      - reinterpret_cast <변환할 타입>(변환 대상)

    (3) 사용 시기

      - 명시적 변환과 동작이 동일 함으로 명시적 변환 대신 사용합니다.

      - 단 const를 사용하는 변환 대상은 사용할 수 없습니다.

    (4) Test Code

      <명시적 형 변환>

#include <iostream>

int main()
{
    int *int_ptr = new int(10);
    char *char_ptr;
    
    std::cout << *int_ptr << std::endl;
    
    char_ptr = reinterpret_cast<char*>(int_ptr); 
    *char_ptr = 20;  // int_ptr 의 값을 변경
    
    std::cout << *int_ptr << std::endl;
    
    return 0;
}   

        <const 지정자 사용 시, 명시적 형 변환>

#include <iostream>

int main()
{
    const int *int_ptr = new int(10);
    char *char_ptr;

    std::cout << *int_ptr << std::endl;

    char_ptr = reinterpret_cast<char*>(const_cast<int*>(int_ptr));
    *char_ptr = 20;  // int_ptr 의 값을 변경

    std::cout << *int_ptr << std::endl;

    return 0;
}

  6) dynamic_cast

    (1)  지원 범위

      - C++ 만 지원합니다. 

    (2) 사용법

      -dynamic_cast <변환할 타입>(변환 대상)

    (3) 사용 시기

      - Class의 포인터 간 형 변환 시, 안전하게 down casting을 위해 사용합니다.

      - Class의 참조 변수간 형 변환 시, 안전하게 down casting을 위해 사용합니다.

      - 단, parent에 virtual 함수가 존재해야 정상 동작합니다.

    (4) Test Code

#include <iostream>


class Parent
{
public:
    Parent() { std::cout << "Parent " << std::endl; }
    virtual ~Parent() { std::cout << "~Parent " << std::endl; }

    void say()
    {
        std::cout << "parent say" << std::endl;
    }
};

class Child : public Parent
{
public:
    Child() { std::cout << "Child " << std::endl; }
    virtual ~Child() { std::cout << "~Child " << std::endl; }

    void say()
    {
        std::cout << "Child say" << std::endl;
    }
};


int main()
{
    Parent* ptr_p_instance = new Child();
    Child* ptr_c_instance;


    ptr_p_instance->say();

    // dynamic_cast를 사용한 down casting 
    ptr_c_instance = dynamic_cast<Child*>(ptr_p_instance);

    if (ptr_p_instance == nullptr) {
        std::cout << "error compile" << std::endl;
    }
    ptr_c_instance->say();


    return 0;
}

>>[C++ 관련 모든 글 보기]

728x90
반응형