반응형
출처 : KGCA 게임 아카데미(http://www.kgcaschool.com/). 수업 예제 파일
참고 :
1) bad_cast 예외
3) using namespace ###; 는 취소할 수 없다. 그래서 using문이 작동하는 범위를 정해버림(..)
4) __int64 == long long 참고
header.h
#pragma once #include <iostream> using std::cout; using std::endl;
dynamic_cast.h
#pragma once #include "header.h" namespace dyn { //dynamic_cast는 vtable을 사용하기 떄문에 반드시 virtual 함수가 있어야 작동한다. class dA { public: virtual void test() { cout << "test in A" << endl; } }; //상속시 접근지정자를 생략하면 class는 private로, struct와 union은 public으로 상속된다. class dB : public dA { public: virtual void test() { cout << "test in B" << endl; } void test2() { cout << "test2 in B" << endl; } }; class dC : public dB { public: virtual void test() { cout << "test in C" << endl; } void test2() { cout << "test2 in C" << endl; } }; //부모 클래스의 레퍼런스를 매개변수로 받는 함수 void Globaltest(dA& da) { try { //매개변수로 받은 a를 B&로 캐스팅 dB& b = dynamic_cast<dB&>(da); cout << "Success cast to B " << endl; } //캐스팅 실패시 dynamic_cast연산자는 예외 클래스 std::bad_cast를 던진다. catch (std::bad_cast) { cout << "Can't cast to B" << endl; } } }
static_cast.h
#pragma once #include "header.h" namespace sta { using BYTE = unsigned char; // == typedef unsigned char BYTE ; //static_cast : 의미없는 형변환 방지 class sA { public: virtual void Test() {} }; class sB : public sA { //내용이 없다(..) }; class sD { public: float m_fValue; //operator sC() //{ // //멤버 초기화 // sD fRet = { static_cast<int>(m_fValue) }; // return fRet; //} }; class sC { public: int m_iValue; operator sD() { //멤버 초기화 sD fRet = { static_cast<float>(m_iValue) }; return fRet; } }; //함수들 void func() { BYTE ch = 'a'; int i = 75; float f = 2.5f; double db = 3.14; cout << ch << " " << i << " " << f << " " << db << endl; BYTE chi = static_cast<BYTE>(i); //int to BYTE(unsigned char); int ich = static_cast<int>(ch); //BYTE(unsigned char) to int float fdb = static_cast<float>(db); //double to float; double dbf = static_cast<double>(f); //float to double; cout << chi << " " << ich << " " << fdb << " " << dbf << endl; //이런식의 형변환은 컴파일러가 방법을 모르므로 불가능하다. //sA aaa = static_cast<sA>(ch); } void func(sA* pa, sB* pb) { //sA(부모)의 포인터를 sB(자식)의 포인터로 형변환 시도 //안전하지 않다. (unsafe conversion) sB* pb1 = dynamic_cast<sB*>(pa); sB* pb2 = static_cast<sB*>(pa); if (pb1 == nullptr) { cout << "pb1 == nullptr 캐스팅 실패" << endl; } else { cout << "pb1 != nullptr 캐스팅 성공" << endl; } if (pb2) { cout << "pb2 != nullptr 캐스팅 성공" << endl; } else { cout << "pb2 == nullptr 캐스팅 실패" << endl; } //sB(자식)의 포인터를 sA(부모)의 포인터로 형변환 시도 //안전하다. (safe conversion); sA* pa1 = dynamic_cast<sA*>(pb); sA* pa2 = static_cast<sA*>(pb); if (pa1 == nullptr) { cout << "pa1 == nullptr 캐스팅 실패" << endl; } else { cout << "pa1 != nullptr 캐스팅 성공" << endl; } if (pa2) { cout << "pa2 != nullptr 캐스팅 성공" << endl; } else { cout << "pa2 == nullptr 캐스팅 실패" << endl; } } void func(sC& pc, sD& pd) { //상속 관계가 아닌 클래스끼리의 형변환은 Dynamic_cast가 허락하지 않는다. // sC* pc1 = dynamic_cast<sC*>(pd); // sD* pd1 = dynamic_cast<sD*>(pc); //static_cast는 컴파일러가 형변환 방법을 알면 변환해준다. //그러나 컴파일러가 형변환 방법을 모르면 알려줘야 한다. //sC pc2 = static_cast<sC>(pd); //형변환 방법 지정 안함 sD pd2 = static_cast<sD>(pc); //형변환 방법 지정 함 cout << "pc.m_iValue : " << pc.m_iValue << endl; cout << "pd.m_fValue : " << pd.m_fValue << endl; cout << "pd2.m_fValue : " << pd2.m_fValue << endl; } }
const_cast.h
#pragma once #include "header.h" namespace con { class cc_test { int number; const int cn; public: void setNumber(int n); void printNumber() const; const int* GetConst(); int* GetNumberPointer(); //const 멤버 변수가 있으면 기본 생성자가 추가되지 않는다. //생성자에서 const 멤버 변수를 초기화해야하기 때문이다. cc_test() : cn(0) {} ~cc_test() {} }; void cc_test::setNumber(int n) { //const_cast<int>cn = n; //const_cast의 형식은 개체 형식에 대한 포인터, 참조 또는 멤버 포인터여야 합니다. number = n; } //멤버함수에 const가 붙으면 그 함수 내에서는 클래스 자체가 const class로 취급된다. void cc_test::printNumber() const { //const 함수에서 멤버 변수의 값을 변경하기(..) cout << "\nBefore : " << number; const_cast<cc_test *>(this)->number--; cout << "\nAfter : " << number; } const int* cc_test::GetConst() { return &number; } int* cc_test::GetNumberPointer() { return &number; } }
reinterpret_cast.h
#pragma once #include "header.h" namespace rei { //reinterpret_cast 강제 형변환에 사용. //보통 포인터->데이터, 포인터->포인터 형변환에 사용된다. unsigned short hash_1(void* p) { //주소를 정수로 변환. unsigned int val = reinterpret_cast<unsigned int>(p); return (unsigned short) (val ^ (val >> 16)); } int g_iArray[10][10]; unsigned short hash_2(void* p) { unsigned short val = reinterpret_cast<unsigned short>(p); return val % 10; } void set(int iRow, int iValue) { for (int iCnt = 0; iCnt < 10; iCnt++) { if (g_iArray[iRow][iCnt] <= 0) { g_iArray[iRow][iCnt] = iValue; break; } } } int get(int iRow, int iValue) { for (int iCnt = 0; iCnt < 10; iCnt++) { if (g_iArray[iRow][iCnt] == iValue) { return g_iArray[iRow][iCnt]; } } return -1; } }
cast_main.cpp
#include "dynamic_cast.h" #include "static_cast.h" #include "const_cast.h" #include "reinterpret_cast.h" int main() { #pragma region dynamic_cast { #define define_dynamic #ifdef define_dynamic using namespace dyn; #endif cout << "dynamic_cast Start" << endl; // 부모 => 자식 (상속관계) // dA => dB => dC //자식의 자식을 동적할당 dA* pa1 = new dC; //가상 함수이므로 실제 자식의 것으로 실행됨. pa1->test(); //자식을 동적할당 dA* pa2 = new dB; //부모에는 test2 함수가 없으므로 호출할 수 없다. //pa2->test2(); //pa1에 들어있는 메모리는 C //그러므로 B(부모)의 포인터로 캐스팅 가능 dB* pb = dynamic_cast<dB*>(pa1); if (pb) { // == if(pb != nullptr) pb->test(); //가상함수인 경우 : 메모리의 함수(class C의 함수) 호출 pb->test2(); //가상함수가 아닌 경우 : 포인터의 함수(class B의 함수) 호출 } //pa2에 들어있는 메모리는 B //그러므로 C(자식)의 포인터로 캐스팅 불가능 dC* pc = dynamic_cast<dC*>(pa2); if (pc != nullptr) { // == if(pc) pc->test(); pc->test2(); } //A(부모)는 B(자식)을 알고 있지 않기 때문에 실패. dA AonStack; Globaltest(AonStack); //B(자신)은 B(자신)을 알고 있으므로 당연히 가능. dB BonStack; Globaltest(BonStack); //C(자식)은 B(부모)를 알고 있으므로 가능. dC ConStack; Globaltest(ConStack); cout << "dynamic_cast End" << endl << endl; #undef define_dynamic } #pragma endregion #pragma region static_cast { #define define_static #ifdef define_static using namespace sta; #endif cout << "static_cast Start" << endl; func(); sA a; sB b; func(&a, &b); sC c; sD d; c.m_iValue = 99; d.m_fValue = 0.99f; func(c, d); cout << "static_cast End" << endl << endl; #undef define_static } #pragma endregion #pragma region const_cast { #define define_const #ifdef define_const using namespace con; #endif cout << "const_cast Start" << endl; cc_test X; X.setNumber(8); X.printNumber(); //1 //int* iValue = X.GetConst(); //반환값이 const인 함수는 const 변수로 받아야 함. const int* iValue = X.GetConst(); //*iValue = 20; //상수 에러 //2 int* iValue2 = const_cast<int*>(X.GetConst()); *iValue2 = 20; X.printNumber(); //이렇게 멤버 변수를 바꿀수도 있구나(...) int* iValue3 = X.GetNumberPointer(); *iValue3 = 30; X.printNumber(); cout << "const_cast End" << endl << endl; #undef define_const } #pragma endregion #pragma region reinterpret_cast { #define define_reinterpret #ifdef define_reinterpret using namespace rei; #endif cout << "reinterpret_cast Start" << endl; //두 개의 값이 동일한 경우 주소를 사용하여 해시값을 얻을 수 있다. //주소를 인덱스에 매핑하는 해시함수에서 reinterpret_cast를 유용하게 사용할 수 있다. int a[3] = { 1,2,3 }; for (int iCnt = 0; iCnt < 3; iCnt++) { cout << a[iCnt] << " " << hash_1(a + iCnt) << endl; } int iArray[100]; //이부분을 왜 이렇게 해놨는지 모르겠음...(...) //여기서부터 for (int iCnt = 0; iCnt < 10; iCnt++) { iArray[iCnt] = iCnt + 1; unsigned short iHash = hash_2(&iArray[iCnt]); set(iHash, iArray[iCnt]); } for (int iCnt = 0; iCnt < 10; iCnt++) { unsigned short iHash = hash_2(&iArray[iCnt]); cout << get(iHash, iArray[iCnt]) << " " << endl; } //여기까지 //주소값을 수치로 바꿔서 주소에 접근하기. __int64 aa = 7; __int64 aaa = reinterpret_cast<__int64>(&aa); __int64* pAAA; cout << aa << endl; pAAA = reinterpret_cast<__int64*>(aaa); *pAAA = 111; cout << aa << endl; cout << "reinterpret_cast End" << endl << endl; #undef define_reinterpret } #pragma endregion }
반응형