코딩 규칙 ! c++에서의 형변환_static_cast 문제점 명시 그리고 해결책_240429 추가함.

보물창고·2022년 1월 17일
0

c++ basic 코드누리

목록 보기
50/50
post-custom-banner

https://ence2.github.io/2020/11/c-%EC%BA%90%EC%8A%A4%ED%8C%85-%EC%B4%9D%EC%A0%95%EB%A6%AC%EC%8A%A4%EB%A7%88%ED%8A%B8%ED%8F%AC%EC%9D%B8%ED%84%B0-%EC%BA%90%EC%8A%A4%ED%8C%85-%ED%8F%AC%ED%95%A8/
// 타이핑 위 글 읽자.

  • c++에서의 하향형변환은 반드시 static_cast 또는 dynamic_cast를
    사용해야 한다.

중요! 240429

언제 static_cast vs 언제 dynamic_cast ??
반환받는 타입과 형변환 대상의 메모리 구조가 동일하다면 static_cast를 사용하자. 하지만 static_cast는 다른 클래스라고 하더라도 메모리 구조가 동일하면 검사도 안하고 그냥 캐스팅 성공시킨다는 특징도 있다.
형변환 대상의 메모리 구조를 정확히 알수 없다면 dynamic_cast를 사용해야 함.

  • static_cast 내용을 보면, 하향형변환에서 생기는 문제에 대해 1번과 2번이 있다. 그리고 해결책으로 제시한 dynamic_cast 예시 코드인
    언제 사용할까? 240429 추가함. 의 코드를 보자.

4개의 형변환이 있음.

1번 타자 - static_cast

정의

: 타입 검사를 하지 않는 컴파일 타임에 처리하는 명시적인 형변환,

단점.

: 하향형변환 후, 발생하는 문제는 사용자가 책임져야 함.

  • 왜 그럴까?
    : 기본 객체만의 정보로 파생 객체의 모든 데이터와 함수를 가질 수 없기 때문.
    //아무리 파생이더라도, 파생만의 상속받지 않은 데이터가 있다.
    //그 데이터를 어떻게 처리할 것인데???
  • 어떤 문제?
    1) 하위 클래스의 멤버가 쓰레기로 나온다던지
    2) 아예 다른 객체 인데, 메모리 구조가 같아서 동일한 값이 대입된다던지.

왜 사용하는 것일까?

  • 하향형변환 시, dynamic_cast 보다 속도가 빠름.
  • 컴파일 시에 형변환을 결정하므로 속도 빠름.

언제 사용할까?

    1. 상속 관계에서의 형변환에 사용함.
      그런데 그에 대한 책임은 전적으로 프로그래머에게 있다.
      -> 프로그래머가 자료형을 명확히 알고 있을 때, 사용하면 효율적임.
    1. c언어에서의 형변환을 대체하는 친구
int iData1 = 200;
int iData2 = 300;

float fData = (float)iData1 / iData2;
//이렇게 썻던 놈을 

float fData2 = static_cast<float>(iData1) / iData2; 
//이런식으로 사용함.

다운캐스팅 예제 코드
: 에러가 발생하는 이유는 28번줄에서 다운캐스팅 시에는 반드시 캐스팅을 명시해야 함.
지금의 경우 메모리 구조가 달라서 바로 대입 불가함.

업캐스팅 예제 코드

-> 상향 형변환은 그냥 해도 되지만, 업캐스팅 했다는 것을
명시하기 위해 static_cast 사용하는 것이 좋음


상향형변환은 언제나 옳다??

-> 컴파일은 문제 없으나, Show 함수를 호출할 때, 2번째와 4번째 줄을 보면, 실타입과는 다르게 포인터 타입의 함수가 호출되는 것을 확인할 수 있음.

왜 그런것일까?
c++은 기본적으로 정적 바인딩을 따르기 때문임.
포인터형의 객체를 자료형으로 삼기 때문이다.
-> 처리하려면, 동적 바인딩 처리하는 가상함수를 사용해야 함.
가상함수는 실행시간에 진짜 정의된 형타입으로 자료형을 결정하기 때문임!

  • virtual을 작성해서 위의 문제를 해결한 코드.

1번. 하향 형변환에서 생기는 문제에 대해

  • Player 객체에는 hp밖에 없는데, Knight 객체에는 power가 있다...
    메모리 구조가 Player에서 Knight로 확장됨, 즉 메모리 구조가 다르기 때문에 발생함.
  • -> 이런 경우에 dynamic_cast를 사용해야 한다.

2번. 하향형변환 이지만 정상적인 상황

  • 객체 생성할 때부터 Knight 클래스를 이용해서 할당했기 때문임.

위의 경우, 하향 형변환이라고 해서 모두 올바른 결과를 가지고 오는 것은 아니다.

하향형 변환 후, 파생 객체의 함수나 데이터 참조 문제
-> 파생이라고 해서 기본 객체가 파생 객체의 모든 멤버와 함수를 가질수 없음.


static_cast의 특징.

정말 큰 문제
-> 아처를 만들었는데, 나이트가 출력되네???? 오잉!!!!
--> static_cast의 문제점이 드러남.

여기서 알 수 있는 것은 클래스의 내부 구조가 같다면, 데이터를 그냥 넣는 것을 확인할 수 있음.
Knight도 int power 멤버를 가지고 있어서 문제 없이 캐스팅 된 것임..

주의할 점

static_cast 캐스팅은 위험함.
-> 하향형변환에 사용할 시 반드시 실제 할당된 클래스를 기준으로 해서 형변환을 해야 함.
: 나이트는 나이트로, 나이트를 아처로 캐스팅 하면 문제...

외부에서 인자로 넘어와서 static_cast를 해야 한다면, 어떻게 처리할 것이냐???

  • 안전장치를 해야함.
    1) dynamic_cast를 한다거나
    2) Knight인지 Archer 인지 추가적인 확인을 해야함.

//루키즈 보고 열혈 복습

2번 타자 - dynamic_cast

정의

: 런타임 도중에 형변환을 결정함.
상속관계에서 다운캐스팅 시 안전하게 캐스팅함.

언제 사용할까? 240429 추가함.

: static_cast의 하향 형변환 문제 1번과 2번에서 확인했듯이,
프로그래머가 형변환 타입에 대해 정확히 확정지을 수 없을때 사용해야 한다.

  • static_cast 에서의 문제가 되었던 코드임.

  • 이를 dynamic_cast로 실행해보자.
    : 다형 특성을 위해서 virtual 작성함.
    -> p1의 메모리 구조는 Player 밖에 모르기 때문에 불가하다

  • 동일한 하향 형변환이지만, Knight의 메모리 구조를 알고 있기 때문에
    지금의 경우는 하향 형변환이 성공함.

왜 사용할까?

: 형변환 시 안전성을 확보하기 위함.

단점.

: static_cast 보다 속도가 느림.

  • 왜 느린 것일까?
    : 런타임 도중에 안정성을 검사하기 위해 컴파일러가 바이너리 코드를 만듬.

특징

  • 상향형변환, 하향형변환 모두 가능.
  • 하향형변환을 하기 위해서는 기본 클래스에 가상함수가 있어야 함.

예시

  • 이전에 static_cast에서 Archer -> Knight 변환이 되는 것과는 다르게, 런타임 도중에 형변환 검사를 체크함.

const_cast

정의

: const를 붙이거나 떼거나.

특징

  • const 상수성을 제거함.

언제 사용할까?

: 기존에 만들어진 함수에 상수형의 변수를 인자로 사용할 때,
예를 들어
매개변수로 전달되는 자료형과 매개변수의 자료형이 const 선언으로 인해불일치한다면, 유용하게 사용할 수 있음.

reinterpret_cast

정의

: 강제 형변환

  • 서로 다른 클래스의 객체포인터형끼리 바꿀 수 있음.
  • 컴파일러가 책임지지 않음.

언제 사용할까?

  • 포인터와 전혀 관계없는 다른 타입변환

  • void형을 반환하는 경우
    예를 들어 malloc

  • 강제 형변환 하는 예제

  • 주소값을 변경시키는 예제.

  • 메모리 풀에도 사용됨.
    -> 다음 주소를 가리키는 용도로 사용함.

  • 다음 메모리를 가리키거나, 이전의 메모리를 가리키거나 할 때 사용하는 듯한데, 이건 나의 유추임..

관련 코드

https://juheel.tistory.com/3

profile
🔥🔥🔥
post-custom-banner

0개의 댓글