C++프로그래밍/이론 정리

형변환 연산자

season97 2023. 12. 4. 12:17
728x90
반응형

▶ C++형변환 연산자의 종류

 

1. static_cast

 

ㆍ 컴파일 시간에 형변환이 이루어지는 가장 일반적인 형변환 연산자.

 

ㆍ 기본 자료형 간의 변환, 객체 포인터 간의 변환, 함수 포인터 간의 변환에 사용

 

ㆍ 예를들어 double을 int로 변환, 부모클래스의 포인터를 자식 클래스의 포인터로 변환할 때 사용

 

double d = 3.14;
int i = static_cast<int>(d);

 

더보기

※ static_cast와 일반 형변환의 차이점

 

ㆍ C++스타일의 형변환 연산자인 static_cast

-> 컴파일 타임에 타입 체크를 수행함, 즉 잘못된 형변환을 시도하면 컴파일 에러 발생

-> static_cast의 역할만 수행

 

ㆍ C스타일의 (type)value

-> 컴파일 타임에 타입 체크를 수행하지 않음, 잘못된 형변환을 시도해도 컴파일 오류가 발생하지 않아 런타임에서 예상치 못한 결과를 초래할 수 있다.

-> 모든 종류의 형변환을 수행할 수 있다, 즉 const_cast, static_cast, reinterpret_cast의 형변환을 모두 수행할 수 있다

 

2. dynamic_cast

 

ㆍ 런타임에 형변환을 수행하는 연산자로, 주로 다형성을 가진 객체의 포인터나 참조형 간의 변환에 사용

 

ㆍ 예를들어 부모클래스 포인터를 자식 클래스 포인터로 변환할 때 변환하려는 객체가 실제로 해당 자식클래스의 인스턴스인지 런테임때 체크함

Base* b_ptr = new Derived;
Derived* d_ptr = dynamic_cast<Derived*>(b_ptr);

동적 형변환이 실패하면 nullptr반환

 

더보기

※ static_cast와 dynamic_cast의 차이

 

ㆍ static_cast는 컴파일 타임에 형변환 유효성을 검사함. 따라서 유효하지 않은 형변환을 시도하면 컴파일 에러가 발생한다. 다만, 형변환의 안정성을 완전히 보장하지는 않음

예를 들어-> 부모 클래스의 포인터를 자식 클래스의 포인터로 형변환 하는 경우(dynamic) 실제로 해당 포인터가 가리키는 객체가 자식 클래스의 인스턴스인지는 검사하지 않는다.

 

ㆍ dynamic_cast는 런타임에 형변환의 유효성을 검사함, 부모 클래스의 포인터를 자식 클래스의 포인터로 형변환 하는 경우 실제로 해당 포인터가 가리키는 객체가 자식 클래스의 인스턴스인지 런타임때 검사함. 만약 실패하면 nullptr을 반환한다.

 

 결론

-> dynamic_cast 의런타임 체크는 약간의 성능 오버헤드를 초래할 수 있다. 형변환이 항상 유효하다는 것을 알고 있을 때는 static_cast 를 사용하는 것이 좋다.

 

 

3. const_cast

 

ㆍ 객체의 상수성을 추가하거나 제거하는데 사용

 

ㆍ const 객체를 non-const로 변환하거나 그 반대를 할 수 있다

const int ci = 10;
int* non_const = const_cast<int*>(&ci);

ㆍ 컴파일러는 const 변수를 최적화 하는데 const속성을 사용하므로, const_cast를 사용해 const 변수를 변경하면 예상치 못한 결과를 초래할 수도 있다.

ㆍ const_cast는 const 속성 뿐만 아니라 volatile속성도 제거할 수 있다. volatile 키워드는 변수가 컴파일러에 의해 최적화 되지 않도록 지시하는 키워드

-> 컴파일러는 코드 최적화를 위해 여러 방법을 사용하는데, 예를들어 반복적인 접근을 줄이기 위해 그 값을 레지스터에 저장하거나, 변하지 않는 값은 미리 계산해두는 방법을 사용한다., volatile 키워드는 이러한 최적화를 적용시키지 않겠다는 키워드

- volatile  사용되는 상황 -

1. 멀티 스레딩 환경에서 한 스레드가 다른 스레드에 의해 변경될 수 있는 변수

2. 하드웨어 레지스터에 직접 매핑된 변수

3. 인터럽트 핸들러에서 사용되는 변수

더보기

※ 사용 예시

void changeValue(int* ptr) 
{
    *ptr = 10;
    std::cout << *ptr << std::endl;
}

int main() 
{
    int x = 5;
    const int* ptr = &x; // x에 대한 const 포인터를 생성
    
    // changeValue 함수는 non-const int*를 인자로 받으므로, ptr을 직접 전달할 수 없다
    // const_cast를 사용하여 ptr의 const 속성을 제거하고, 그 결과를 changeValue 함수에 전달
    changeValue(const_cast<int*>(ptr));
    
    return 0;
}
더보기

ㆍ const_cast 는 주로 const가 아닌 객체에 대한 const포인터나 참조를 non-const포인터나 참조로 변환하는데 사용됨

 

 

※ mutable?

class의 const 맴버 함수 내에서 const값을 변경할 수 있게 해주는 키워드

ㆍ const_cast는 const포인터나 참조의 상수성을 제거하는데 사용, mutable으 const 객체의 맴버 변수를 변경할 수 있게 해주는데 사용 

 

 

 

 

 

4. reinterpret_cast

 

ㆍ 두 포인터 간의 형변환, 포인터와 정수간의 형변환 등 서로 다른 타입의 참조형간의 형변환에 사용

 

ㆍ 비트 단위로 형변환을 수행하므로 매우 낮은 수준의 형변환을 수행하고자 할 때 사용됨

int i = 10;
int* p = &i;
long address = reinterpret_cast<long>(p);

 

더보기

※ 주의점

 

ㆍ 서로 관계가 없는 타입들 간의 변환을 수행한다. 타입 시스템의 규칙을 완전히 무시한다.

 

※ 필요한 경우 

 

하드웨어와 상호작용 하는 경우 :  종종 메모리를 특정 방식으로 해석해야 하는 경우가 있다. 예를들어 레지스터에 접근하거나 네트워크 패킷을 분석하는 경우에는 reinterpret_cast를 사용해 원시 메모리를 특정 구조체로 해석할 수 있다.

 

ㆍ  정수를 포인터로 변환하거나 그 반대를 수행하는 경우 : 종종 임베디드 시스템과 같이 주소가 고정된 하드웨어 리소스에 접근해야 할 때 유용

 

ㆍ  바이트 스트림을 특정 타입으로 해석하는 경우 : 바이너리 파일을 읽거나 네트워크를 통해 데이터를 전송받는 경우, 데이터는 일반적으로 바이트 스트림으로 전달됨. 이러한 바이트 스트림을 특정 타입의 객체로 해석려면 reinterpret_cast를 사용할 수 있다

728x90
반응형