본문 바로가기
<개인공부>/[C++]

[C++] dynamic_cast (타입캐스트 연산자)

by 사용자 BlockDMask 2018. 7. 25.
반응형
  • 안녕하세요. BlockDMask 입니다.

  • 이번에는 C++의 네가지 타입캐스트 연산자
    (static_cast, const_cast, reinterpret_cast, dynamic_cast) 중에서
    마지막 dynamic_cast에 대해서 알아보겠습니다.

> dynamic_cast 에 대해서.

  • dynamic_cast는 safe downcasting(안전한 다운캐스팅)에 사용이 됩니다. (물론 upcasting에도 쓰입니다)

  • 조금 쉽게 말씀 드리자면, 부모 클래스의 포인터에서 자식 클래스의 포인터로 다운 캐스팅 해주는 연산자 입니다.
    (부모클래스의 포인터가 실제 무엇을 가리키고 있는지가 중요합니다)

  • 하지만, 런타임 시간에 실제로 해당 타입이 다운 캐스팅이 가능한지 검사하기 때문에, 런타임 비용이 조금 높은 캐스트 연산자 입니다.

  • dynamic_case<new_type>(expression)

  • dynamic_case<바꾸려는 새로운 타입>(대상)

  • ex) dynamic_cast<childClass*>(pParent*);

  • 성공할 경우 : new_type의 value를 return 합니다.

  • 실패할 경우(new_type = pointer) : null pointer

  • 실패할 경우(new_type = reference) : bad_cast (exception 처리됩니다.)


> 예제1 (다운 캐스팅 1) 

  • "부모클래스의 생성자로 생성되었고 부모 포인터가 가리키고 있는 클래스"를 자식클래스 포인터로 형변환(dynamic_cast) 할때.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <iostream>
using namespace std;
class Blog
{
public:
    Blog() { cout << "Blog()\n"; };
    virtual ~Blog() { cout << "~Blog()\n"; };
 
    void Show()
    {
        cout << "This is Blog Class\n";
    }
};
 
class Tistory : public Blog
{
public:
    Tistory() { cout << "Tistory()\n"; };
    virtual ~Tistory() { cout << "~Tistory()\n"; };
 
    void Show()
    {
        cout << "This is Tistory Class\n";
    }
};
 
int main(void)
{
    Blog* pBlog = new Blog();
 
    //출력됩니다.
    pBlog->Show();
 
    Tistory* pTistory = dynamic_cast<Tistory*>(pBlog);
    if (pTistory == nullptr)
    {
        //티스토리 클래스의 포인터가 nullptr이 나올떄.
        cout << "Runtime Error\n";
    }
    else
    {
        pTistory->Show();
    }
    
    delete pBlog;
    system("pause");
    return 0;
}
cs


  • 결과 : runtime error 가 발생하게 됩니다.
  • 이유 : new Blog()를 통해서 생성 되었기 때문에, 당연하게도 Tistory 생성자는 불리지 않았습니다.
  • 생성자도 불리지 않았는데, 무슨 해당 타입으로 포인터를 만들까요.


> 예제2 (다운 캐스팅 2)
  • "자식클래스의 생성자로 생성되었고 부모클래스 포인터가 가리키고 있는 클래스"를 자식클래스로 형변환(dynamic_cast) 할때
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <iostream>
using namespace std;
class Blog
{
public:
    Blog() { cout << "Blog()\n"; };
    virtual ~Blog() { cout << "~Blog()\n"; };
 
    void Show()
    {
        cout << "This is Blog Class\n";
    }
};
 
class Tistory : public Blog
{
public:
    Tistory() { cout << "Tistory()\n"; };
    virtual ~Tistory() { cout << "~Tistory()\n"; };
 
    void Show()
    {
        cout << "This is Tistory Class\n";
    }
};
 
int main(void)
{
    Blog* pBlog = new Tistory();
 
    //출력됩니다.
    pBlog->Show();
 
    Tistory* pTistory = dynamic_cast<Tistory*>(pBlog);
    if (pTistory == nullptr)
    {
        //티스토리 클래스의 포인터가 nullptr이 나올떄.
        cout << "Runtime Error\n";
    }
    else
    {
        pTistory->Show();
    }
    
    delete pBlog;
    system("pause");
    return 0;
}
cs


  • 결과 : 자식클래스의 포인터로 다운캐스팅이 잘 됩니다.

  • 바뀐부분은 Blog* pBlog = new Tistory(); 요기 하나 뿐 입니다. 

  • 중요한것 1) 부모 클래스(Blog)의 포인터로 자식클래스(Tistory)를 가리킬 수 있습니다.

  • 중요한것 2) pBlog->Show()는 실제 pBlog가 가리키는 클래스는 본인의 자식클래스인 Tistory 클래스 이지만, virtual로 선언되어있지 않기 때문에 pBlog가 가지고 올 수 있는 것은 본인의 Show() 함수 입니다.

  • 제일 중요) pBlog가 실제 가리키는 클래스(new를 통해 생긴 클래스)는 자기 자식인 Tistory 클래스 이므로 dynamic_cast를 통해서 다운캐스팅이 가능합니다.


> 예제3 (업 캐스팅) 
  • "자식클래스의 생성자로 생성되었고 자식클래스 포인터가 가리키고 있는 클래스"를 부모클래스로 형변환(dynamic_cast) 할때 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <iostream>
using namespace std;
class Blog
{
public:
    Blog() { cout << "Blog()\n"; };
    virtual ~Blog() { cout << "~Blog()\n"; };
 
    void Show()
    {
        cout << "This is Blog Class\n";
    }
};
 
class Tistory : public Blog
{
public:
    Tistory() { cout << "Tistory()\n"; };
    virtual ~Tistory() { cout << "~Tistory()\n"; };
 
    void Show()
    {
        cout << "This is Tistory Class\n";
    }
};
 
int main(void)
{
    Tistory* pTistory = new Tistory();
 
    //출력됩니다.
    pTistory->Show();
 
    Blog* pBlog = dynamic_cast<Blog*>(pTistory);
    if (pBlog == nullptr)
    {
        //티스토리 클래스의 포인터가 nullptr이 나올떄.
        cout << "Runtime Error\n";
    }
    else
    {
        pBlog->Show();
    }
    
    delete pTistory;
    system("pause");
    return 0;
}
cs


 

  • 결과 : 부모클래스로 업캐스팅이 잘 됩니다.

  • 이유 : 자식클래스의 생성자가 불리면, 자연스레 부모클래스의 생성자도 불리게 됩니다. (부모클래스 생성자가 먼저 불립니다.)

  • 이렇게 때문에 당연하게도 부모 클래스에 대한 함수들을 부를 수 있게 됩니다. 

  • 이유 : pBlog->Show() 에서 부모의 Show가 불리는 이유는 virtual 선언을 하지 않아서 입니다.

<자료참고>

http://en.cppreference.com/w/cpp/language/dynamic_cast

https://msdn.microsoft.com/ko-kr/library/cby9kycs.aspx

읽어주셔서 감사합니다.


반응형

댓글1