본문 바로가기

C

c++ 다운캐스팅 시 static cast 절대 쓰지 말자, dynamic_cast

RTII를 피하라

RTII(Run time type information)

 

static_cast는 절대 쓰지 말자.

type이 같지 않은 것을 conversion 하여 프로그램이 터질 수 있다.

 

그나마 안전한 것이 dynamic_cast이다.

dynamic_cast는 타입이 같지 않으면 nullptr을 반환한다.

 

코드 >>

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include <iostream>
// Avoid using Run Time Type Information(RTTI)
 
class Animal
{
public:
    virtual ~Animal() = default;
    virtual void speak()
    {
        std::cout << "animal" << std::endl;
    }
private:
    double animalData;
};
 
class Cat : public Animal
{
public:
    void speak() override
    {
        std::cout << "meow~" << std::endl;
    }
    void knead()
    {
        std::cout << "kkuk kkuk" << std::endl;
    }
};
 
class Dog : public Animal
{
public:
    void speak() override
    {
        std::cout << "bark!" << std::endl;
    }
    void wagTail()
    {
        std::cout << "wagging" << std::endl;
    }
private:
    double dogData;
};
 
int main()
{
    // prefer smartPtr
    //Cat* catPtr = new(); 
    // UPCAST, implicit
    Animal* animalPtr = new Cat();
    //Animal* animalPtr = static_cast<Animal *>(catPtr);
    //animalPtr->speak(); // 가능
 
    // downcast (base cast * -> derived cast *)
 
 
    // Warning!
    // static_cast는 아주 아주 위험한 방법의 Casting이다.
    // Dog으로 정의했는데 고양이로 바꾼다...
    // 존재하지 않는 메모리에 Access 함으로써 프로그램이 터질 수 있다.
 
    // 이를 방지하기 위해서 dynamic_cast를 쓰자
    // 만약 type이 같지 않으면 nullptr을 반환한다.
    //Cat* catPtr = static_cast<Cat*>(animalPtr);
    Cat* catPtr = dynamic_cast<Cat*>(animalPtr); // TypeInfo 기능으로 구현이 된다. typeid(Cat).name()
    if (catPtr == nullptr)
    {
        std::cout << "This is not a Cat object" << std::endl;
        return 0;
    }
    catPtr->knead();
    //animalPtr->knead(); // 불가
    delete animalPtr;
 
    // type info
    std::cout << typeid(Animal).name() << std::endl;
    std::cout << typeid(Cat).name() << std::endl;
    std::cout << typeid(Dog).name() << std::endl;
    return 0;
 
}