cpp06

YP J·2022년 6월 25일
0

CppModule

목록 보기
7/9

https://headerfile.tistory.com/64

reinterpret_cast 연산자

  • 어떤 포인트 타입을 다른 포인터 타입으로 변경할 수 있다.
  • 또한 어떤 정수 타입을 포인터 타입으로 변경할수 있고 그 반대도 가능
  • 잘못된 reinterpret_cast 사용은 안전하지 않다.
  • 원하는 변환이 본질적으로 낮은 레벨에서 작동한다면 다른 연산자를 사용해야 한다.
  • 예를들어 char 를 int 로 변환 하거나
  • one class 를 unrelated_class 로 변환 하는 작업은 안전 하지 않다.
  • const, volatile, _unaligned 속성은 제거 할 수없다.
  • null 포인터 값을 목적지 타입의 null포인터 값으로 바꿀수 있다.
  • 한가지 사용방법은 해시함수에 사용할 수있다.
    • 다른 타입의 키와 value값을 연결시켜 줄수 있기 때문이다.

volitile로 선언된 변수는 외부적인 요인으로 그 값이 언제든지 바뀔 수 있음을 뜻한다. 따라서 컴파일러는 volitile 선언된 변수에 대해서는 최적화를 수행하지 않는다. volitile 변수를 참조할 경우 레지스터에 로드된 값을 사용하지 않고 매번 메모리를 참조한다.

#include <iostream>
using namespace std;

// Returns a hash code based on an address
unsigned short Hash( void *p ) {
   unsigned int val = reinterpret_cast<unsigned int>( p );
   return ( unsigned short )( val ^ (val >> 16));
}

using namespace std;
int main() {
   int a[20];
   for ( int i = 0; i < 20; i++ )
      cout << Hash( a + i ) << endl;
}

Output:
64641
64645
64889
64893
64881
64885
64873
64877
64865
64869
64857
64861
64849
64853
64841
64845
64833
64837
64825
64829

const_cast

  • 어떤 오브젝트를 가리키는 포인터나 데이터 멤버를 가리키는 포인터, 레퍼런스에 대해 const, volatile, _unaligned 속성을 제외할 수 있습니다.
  • 포인터와 참조의 경우 결과는 원래 객체를 참조합니다.
  • 데이터 멤버에 대한 포인터의 경우 결과는 데이터 멤버에 대한 원래 (캐스트되지 않은) 포인터와 동일한 멤버를 참조합니다.
  • 레퍼런스된 오브젝트에 따라 쓰기 연산은 정의되지 않은 행동을 일으킬 수 있습니다.
  • const_cast 연산자를 const 변수에 직접적으로 사용할 수 있고 const_cast 연산자는 null포인터 값을 목적지의 nullptr 값으로 변경할 수 있습니다.

static_cast

  • static_cast 는 포인터를 부모 클래스로 변환할때 사용할수있다.
    하지만 안전하지 않다.

    (dynamic_cast 로 하면 에러 날것이다.) 왜냐면 다운캐스팅을 막기 때문 다이나믹은

  • static_cast는 주로 숫자 데이터 형식을 변환 하는데 쓰인다.

  • 열거형을 정수형으로 바꾸거나 정수형을 부동소수점형으로 바꾸는등 데이터의 변환이 확실히 가능한 곳에 쓸 수 있다.

  • static_cast는 런타임 검사를 하지 않으므로

  • dynamic_cast 보다 안전하지 않다.

  • dynamic_cast는 모호한 포인터는 실패한다. but

  • static_cast는 모호한 포인터도 이상없다 판단한다.

dynamic_cast

  • 포인터 타입에 경우 nullptr을 반환하고 레퍼런스 타입의 경우 bad cast exception 예외가 발생합니다.
class A {virtual void f();};
class B : public A {virtual void f();};
class C : public A { };
class D {virtual void f();};
class E : public B, public C, public D {virtual void f();};

void f(D* pd) {
   B* pb = dynamic_cast<B*>(pd);   // cross cast
   A* pa = pb;   // upcast, implicit conversion
}
  • dynamic_cast는 크로스 캐스트가 가능합니다. 동일한 클래스 상속구조에서 완벽한 E객체에 대해 B에서 D로 변환을 할 수 있습니다. D포인터를 B로 바꾼 뒤 A로 바꾸는 연산도 가능합니다.
  • 여러 상속이 이루어진 경우 모호함이 발생할 수 있습니다. D를 가리키는 포인터는 안전하게 B나 C로 변환 될 수 있습니다. 하지만 D를 바로 A로 변환하고자 할 때 모호함이 발생될 수 있습니다.

For each exercise, the type conversion must be solved using one specific type of casting.
Your choice will be checked during defense.

ex00

Conversion of scalar types
Turn-in directory : ex00/
Files to turn in : Makefile, *.cpp, *.{h, hpp}
Allowed functions : Any function to convert from a string to an int, a
float or a double. This will help, but won’t do the whole job.
  • (우리가 직접 캐스팅 하라고 지정하는 명시적 (explicit)캐스팅)
ptr = (Something *)other_ptr;
int_variable = (int)float_variable;
  • But 말도 안되는 캐스팅에 대해서 컴파일러가 오류를 발생시키지 않는다.

static_cast :
우리가 흔히 생각하는, 언어적 차원에서 지원하는 일반적인 타입변환

const_cast:(포인터 및 참조형에서만 사용 가능하며)
객체의 상수성(const) 를 없애는 타입변환, 쉽게 말해 const int 가 int 로 바뀐다

dynamic_cast:
파생 클래스 사이에서의 다운캐스팅(->정확한 의미는 나중에~)

  • Class의 포인터 간 형 변환 시, 안전하게 down casting을 위해 사용합니다.
  • Class의 참조 변수간 형 변환 시, 안전하게 down casting을 위해 사용합니다.
  • 단, parent에 virtual 함수가 존재해야 정상 동작합니다.

reinterpret_cast:

  • (단 const를 사용하는 변환 대상은 사용할 수 없습니다.)
  • 위험을 감수하고 하는 캐스팅으로 서로 관련이 없는 포인터들 사이의 캐스팅 등.

(원하는 캐스팅 종류)<바꾸려는 타입>(무엇을 바꿀 것인가?)
static_cast(float_variable);
static_cast로 float 타입의 float_variable이라는 변수를 int타입의 변수로 타입 변환.

  • Lastly,display the results as shown below.

  • If a conversion does not make any sense or overflows,

  • display a message to inform the user that the type conversion is impossible.

  • Include any header you need in order to handle numeric limits and special values.

./convert 0
char: Non displayable
int: 0
float: 0.0f
double: 0.0
./convert nan
char: impossible
int: impossible
float: nanf
double: nan
./convert 42.0f
char: '*'
int: 42
float: 42.0f
double: 42.0

ex00

  • 형변환 클래스 만드는 과제
  • 먼저 입력 받은 값의 타입을 찾고, 입력값을 char, int, float, double형으로 각각 캐스팅한 값을 출력한다.

char literals

  • ex) ’c’, ’a’, ...
  • 출력가능한 범위에 있으면 해당 문자 출력
  • non displayable이면 Non displayable 출력
  • 애초에 char 타입 범위를 넘어서는 값이면 impossible 출력

int literals

  • ex) 0, -42, 42...

float literals

  • ex) 0.0f, -4.2f, 4.2f...
  • nan은 nanf로
  • inf는 inff로
  • -inf는 -inff로

double literals

  • ex) 0.0, -4.2, 4.2...
  • nan은 nan으로
  • inf는 inf로
  • -inf는 -inf로

Serialization

  • A->B , B->A
  • A를 B로 변환하고, 다시 B를 A로 변환 하는 것을 Serialization 이라한다.
  • 직렬화와 역직렬화
    • 자바직렬화란 자바 시스템 내부에서 사용되는 객체 또는 데이터를 외부의 자바 시스템에서도 사용 할 수있도록 바이트 형태로
    • 데이터 변환 하는 기술(직렬화) 과 바이트로 변환된 데이터를 다시 객체로 변환 하는 기술 (역질렬화) 을 아룰러서 이야기한다.

uintptr_t

  • uintptr_t 는 unsigned long의 별칭이다.
  • 포인터가 참조하는 주소를 숫자로 저장하기 위해 이용된다.
  • #include <cstdint> 에 정의 되어 있다.

ex01

Exercise : 01
Serialization
Turn-in directory : ex01/
Files to turn in : Makefile, *.cpp, *.{h, hpp}
Forbidden functions : None
  • Implement the following functions:
    uintptr_t serialize(Data* ptr);

  • It takes a pointer and converts it to the unsigned integer type uintptr_t.
    Data* deserialize(uintptr_t raw);

  • It takes an unsigned integer parameter and converts it to a pointer to Data.

Write a program to test that your functions works as expected.

  • You must create a non-empty (it means it has data members) Data structure.

  • Use serialize() on the address of the Data object and pass its return value to deserialize().

  • Then, ensure the return value of deserialize() compares equal to the original pointer.

  • Do not forget to turn in the files of your Data structure.

reinterpret_cast

  • reinterpret_cast느ㄴ 임의의 포인터 타입끼리 변환을 허용하는 캐스트 연산자.
  • reinterpret_cast 연산자는 전혀 상관이 없는 자료형으로의 형 변환에 사용된다.
  • 이렇게 reinterpret_cast연산자는 포인터를 대상으로하는, 그리고 포인터와 관련이 있는 모든 유형의 형변환을 허용한다.
  • 데이터의 값이 아닌 바이너리 값 자체를 복사해준다.

uintptr_t

  • 포인터에 대한 비트연산을 할 때 쓰일수 있다.

uinptr_t serialize(Data *ptr);

  • Data 포인터를 uintptr_t 타입으로 캐스팅 해서 반환

Data* deserialize(uintptr_t raw);

  • uintptr_t 타입을 Data 포인터로 캐스팅해서 변환

ex02

Exercise : 02
Identify real type
Turn-in directory : ex02/
Files to turn in : Makefile, *.cpp, *.{h, hpp}
Forbidden functions : std::typeinfo
  • Implement a Base class that has a public virtual destructor only.

  • Create three empty classes A, B and C, that publicly inherit from Base.

  • 이클래스 4개는 캐노니컬 뭐시기 안 지켜도 됨.

  • Base * generate(void);

    • It randomly instanciates A, B or C and returns the instance as a Base pointer.
    • Feel free to use anything you like for the random choice implementation.
  • void identify(Base* p);

    • It prints the actual type of the object pointed to by p: "A", "B" or "C".
  • void identify(Base& p);

    • It prints the actual type of the object pointed to by p: "A", "B" or "C".
    • Using a pointer inside this function is forbidden.
  • Including the typeinfo header is forbidden.
    Write a program to test that everything works as expected.


dynamic_cast:

파생 클래스 사이에서의 다운캐스팅

  • Class의 포인터 간 형 변환 시, 안전하게 down casting을 위해 사용합니다.
  • Class의 참조 변수간 형 변환 시, 안전하게 down casting을 위해 사용합니다.
  • 단, parent에 virtual 함수가 존재해야 정상 동작합니다.
profile
be pro

0개의 댓글