: 부모에서 자식으로의 형변환은 되지 않지만, 전혀 연관이 없는 클래스 간의
형변환이 가능한 것은 의문이다.(static_cast, reinterpret_cast에서 )
허용하는 이유는 그렇게 사용해야만 하는 경우가 있기 때문이다. 알아보자!
-> 추상자료형을 넣는다면 문제가 되지 않지만, 부모를 넣는다면 미정 동작한다.
원래는 CChild객체에 대해서만 형변환을 허용한다면 더욱 안전할지 않을까란 생각을 하게된다.
그런 생각에서 나온 개념이 dynamic_cast이다.
런타임 타입 정보를 사용하여 타입변환을 하는 연산자이다.
실행시간에 타입 정보를 검사하여 제대로 된 형변환만을 허용하기 때문에,
안전성 면에서는 뛰어나지만, 성능을 좋지 않다.
~~ 아 어렵다...~~
dynamic_cast를 이용하면 가상상속에서의 형변환을 어느 정도 해결할 수 있다.
강제형변환이나 static_cast의 경우, 일반 상속이면 타입 변환이 허용되고, 가상상속에서는 타입 변환이 거부된다. 하지만 dynamic_cast의 경우에는 실제 타입에 따라서 안전하게 타입 변환을 해준다는 점에서 의미가 있다.
형변환이 실패할 경우, 포인터형이었다면 nullPtr을 반환하고,
레퍼런스 형이었다면 예외처리된다.
하나 이상의 virtual이 존재해야 한다.
dynamic_cast가 static_cast이나 강제형변환보다 안전한 이유는..
static_cast나 강제 형변환으로 부모를 자식으로 변환할 경우,
성공은 하지만,,, 자식 멤버의 값은 어떻게 될지 미정이다.
but, dynamic_cast의 경우, 실패하면 null이나 예외처리를 하므로
비교적 안전하다.
#include <iostream>
using namespace std;
class CparentA
{
public :
virtual ~CparentA() {}
};
class CparentB
{
public:
virtual ~CparentB() {}
};
class child : public CparentA, public CparentB
{
public :
int val;
};
int main()
{
{
child c;
CparentA *pA = dynamic_cast<CparentA *>(&c);
CparentB *pB = dynamic_cast<CparentB *>(&c);
}
{
CparentA a;
child *pc1 = dynamic_cast<child *>(&a);
if (pc1 == nullptr)
cout << "pc1은 nullptr입니다." << endl;
CparentB b;
child *pc2 = dynamic_cast<child *>(&b);
if (pc2 == nullptr)
cout << "pc2은 nullptr입니다." << endl;
child *pc3 = static_cast<child *>(&a);
cout << "pc3의 멤버 값은 "<< pc3->val << endl;
child *pc4 = static_cast<child *>(&b);
cout << "pc4의 멤버 값은 " << pc4->val << endl;
}
}
: static_cast 사용
-> 예외처리를 통해 안전한 형변환을 확인할 수 있다.
#include <iostream>
using namespace std;
class parent
{
public :
char mValue;
virtual ~parent() {}
};
class child : public parent
{
public:
child()
{
mValue = 1;
mChildValue = 2;
}
int mChildValue;
};
int GetValue(parent * pParent)
{
if (pParent->mValue == 1)
{
child *pC = dynamic_cast<child*>(pParent);
if (pC != nullptr)
{
return pC->mChildValue;
}
else
{
return 0;
}
}
return 0;
}
int main()
{
child c;
cout << (GetValue(&c)) << endl;
parent p;
p.mValue = 1;
cout << (GetValue(&p)) << endl;
}