본문 바로가기
OLD/[C++]개념정리

[개탱][C++][Dynamic Binding][동적 바인딩]

by 개탱 2018. 1. 2.
728x90

Dynamic Binding(동적 바인딩)

<-> Static Binding (정적 바인딩)

 

 - 함수 호출을 위한 바인딩이 실행시에 이루어지는 제도

 - 규칙 -

i) Pointer를 이용하여 함수를 호출한다.

ex[ x->f() ]

ii) Virtual(가상함수)

 

 

우리가 간단하게 동물과 관련된 프로그램을 만든다고 생각을 하고 코딩을 해보자

[먹고 울어대는 함수만 구현]

 

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
#include <stdio.h>
 
class Elephant{
    int age;
    int totalTon;
 
public :
    Elephant(int n) {
        age = n;
        totalTon = 0;
    }
 
    void eat() {
        printf("이 코끼리가 %d그램 먹었습니다.\n", age*1);
        totalTon = totalTon + age*1;
    }
    void makeSound() {
        printf("뿌우 ~~\n");
    }
};
class Rabbit {
    int age;
    double totalGram;
public :
    Rabbit(int n) {
        age = n;
        totalGram = 0;
    }
 
    void eat() {
        printf("이 토끼가 %f그램 먹었습니다.\n", age*0.8);
        totalGram = totalGram + age*0.8;
    }
    void makeSound() {
        printf("찍찍 ~~\n");
    }
};
class Tiger {
    int age;
    int totalRabbit;
 
public :
    Tiger(int n) {
        age = n;
        totalRabbit = 0;
    }
 
    void eat() {
        printf("이 호랑이가 %d그램 먹었습니다.\n", age*5);
        totalRabbit = totalRabbit + age*5;
    }
    void makeSound() {
        printf("어흥 ~~~\n");
    }
}; 
 
int main()
{
    Tiger x(2);
    Rabbit y(3);
    Rabbit yy(2);
    Elephant z(3);
    for(int i = 0; i << 3; i++)
    {
        x.eat();
        y.eat();
        yy.eat();
        z.eat();
        x.makeSound();
        y.makeSound();
        yy.makeSound();
        z.makeSound();
    }
 
}
 
cs

 

위 코드를 보고있으니 각 클래스별로 int age가 반복되고 있음을 볼 수 있다.

그러므로 자신들의 부모클래스를 하나 정해서 그곳에 int age 를 하나 넣어줘서 따로 생성을 하지말자.. 라고 생각할 수 있다.

 

그러므로 

1
2
3
4
5
6
7
class Animal{
protected:
    int age;
    Animal(int n) {
        int age = n;
    }
};
cs

위 코드와 같이 Animal 이라는 클래스를 하나 생성을 해준 뒤

(ex 코끼리)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Elephant : public Animal{
    int totalTon;
 
public :
    Elephant(int n) : Animal(n){
        totalTon = 0;
    }
 
    void eat() {
        printf("이 코끼리가 %d그램 먹었습니다.\n", age*1);
        totalTon = totalTon + age*1;
    }
    void makeSound() {
        printf("뿌우 ~~\n");
    }
};
cs

 

위 코드와 같이 Animal 클래스를 상속시켜주고 생성자에 Animal(int n) 생성자를 호출시켜준다.

또한 Animal 부모클래스에 int age; 가 있기때문에 Elephant 클래스 내부에 int age를 지워준다.

(호랑이와 토끼도 똑같이 수정)

 

그뒤 이대로 코드를 진행을 해주면 동물의 수가 추가될때마다 코드를 추가시켜줘야하니

너무 고정된듯한 느낌이 난다. 그러므로 보통은 Linked_List를 구현해서 하는게 맞지만

지금은 배열로만 구현을 해보겠다.

 

먼저 여러마리를 넣는다고하면 보통 Tiger 배열 , Rabbit 배열.. Elephant 배열.. 이렇게 하나하나 추가를 해주어야하지만

 

지금같은 경우에는 Tiger Rabbit Elephant 클래스 모두 Animal이라는 클래스를 상속을 받고있다.

그러므로 같은 Animal 이라는 타입으로 배열을 만들면 되지만

1
Animal a[10];
cs

 

위와 같은 코드는 Animal이라는 클래스의 객체만 받아와서 배열내부에 

int age; 라는 변수만 있기때문에 

Elephant로 사용을 하기에는 ex) totalTon 과 같은 변수를 사용이 불가능해진다.

 

그래서 우리가 사용하는 방식으로는 

1
Animal *list[10];
cs

 이와 같이 Pointer로 사용을 진행한다.

이를 우리는 UpCasting 이라고 부른다.

UpCasting ( 하위클래스에서 상위 클래스로 해석을 하는 것 )

DownCasting ( 상위클래스를 하위 클래스로 해석을 하는 것 ) (보통 하면안됨)

그뒤

1
2
3
4
5
6
7
8
9
10
    list[0= new Tiger(2);
    list[1= new Rabbit(3);
    list[2= new Rabbit(2);
    list[3= new Rabbit(5);
    list[4= new Elephant(1);
    list[5= new Tiger(2);
    list[6= new Elephant(7);
    list[7= new Rabbit(3);
    list[8= new Rabbit(9);
    list[9= new Tiger(1);
cs

 위와 같이 Dynamic Allocation 으로 동적할당을 진행해주고 나면

분명 하나하나의 객체는 Tiger, Rabbit, Elephant 이지만 하나의 Animal로 묶어줄수가 있다.

자 이제 이것들의 eat() 함수와 makesound() 함수를 진행시키려할때

for문 한번으로 진행을 시키기 위해서

 

Animal 클래스 내부에 int Type라는 것을 선언을 해주고

1
2
3
4
5
6
7
8
9
10
11
class Animal{
protected:
    int age;
    int type;
    Animal(int n) {
        int age = n;
    }
    int getType() {
        return type;
    }
};
cs

 

이제 하위 각 클래스마다 

ex) Elephant 클래스

생성자를 

1
2
3
4
Elephant(int n) : Animal(n){
        type = ELEPHANT;
        totalTon = 0;
    }
cs

 

와 같이 수정을 해준다.

 

그뒤 Main에서 각각의 eat함수와 MakeSound 함수를 생성을 시켜주고 나면

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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#include <stdio.h>
 
#define TIGER (1)
#define ELEPHANT (2)
#define RABBIT (3)
 
class Animal{
protected:
    int age;
    int type;
public:
    Animal(int n) {
        age = n;
    }
    int getType() {
        return type;
    }
};
 
 
class Elephant : public Animal{
    int totalTon;
 
public :
    Elephant(int n) : Animal(n){
        type = ELEPHANT;
        totalTon = 0;
    }
 
    void eat() {
        printf("이 코끼리가 %d그램 먹었습니다.\n", age*1);
        totalTon = totalTon + age*1;
    }
    void makeSound() {
        printf("뿌우 ~~\n");
    }
};
class Rabbit : public Animal{
    double totalGram;
public :
    Rabbit(int n)  : Animal(n){
        type = RABBIT;
        totalGram = 0;
    }
 
    void eat() {
        printf("이 토끼가 %f그램 먹었습니다.\n", age*0.8);
        totalGram = totalGram + age*0.8;
    }
    void makeSound() {
        printf("찍찍 ~~\n");
    }
};
class Tiger : public Animal{
    int totalRabbit;
 
public :
    Tiger(int n)  : Animal(n){
        type = TIGER;
        totalRabbit = 0;
    }
 
    void eat() {
        printf("이 호랑이가 %d그램 먹었습니다.\n", age*5);
        totalRabbit = totalRabbit + age*5;
    }
    void makeSound() {
        printf("어흥 ~~~\n");
    }
}; 
 
int main()
{
 
    Animal *list[10];
 
    list[0= new Tiger(2);
    list[1= new Rabbit(3);
    list[2= new Rabbit(2);
    list[3= new Rabbit(5);
    list[4= new Elephant(1);
    list[5= new Tiger(2);
    list[6= new Elephant(7);
    list[7= new Rabbit(3);
    list[8= new Rabbit(9);
    list[9= new Tiger(1);
    for(int i = 0; i < 10; i++)
    {
        Animal *= list[i];
        if(p->getType() == ELEPHANT) {
            Elephant *= (Elephant *)p;
            q->makeSound();
        }else if (p->getType() == TIGER) {
            ((Tiger *)p)->makeSound();
        }else if (p->getType() == RABBIT) {
            ((Rabbit *)p)->makeSound();
        }
    }
 
    for(int i = 0; i < 10; i++)
    {
        Animal *= list[i];
        if(p->getType() == ELEPHANT) {
            Elephant *= (Elephant *)p;
            q->eat();
        }else if (p->getType() == TIGER) {
            ((Tiger *)p)->eat();
        }else if (p->getType() == RABBIT) {
            ((Rabbit *)p)->eat();
        }
    }
}
cs

 

와 같이 수정이 진행된다.

그런데 생각을 해보면 각 함수별로 중복되는게 

age뿐만이 아니라 eat함수, makeSound 함수 역시도 이름이 중복되고있는데

굳이 저렇게 나누어서 실행을 해야되나 싶다..

 

여기서 나오는게 우리가 맨위에 설명을 해둔 Dynamic Binding(동적 바인딩) 이다.

 

 

먼저 Main함수를

 

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
int main()
{
 
    Animal *list[10];
 
    list[0= new Tiger(2);
    list[1= new Rabbit(3);
    list[2= new Rabbit(2);
    list[3= new Rabbit(5);
    list[4= new Elephant(1);
    list[5= new Tiger(2);
    list[6= new Elephant(7);
    list[7= new Rabbit(3);
    list[8= new Rabbit(9);
    list[9= new Tiger(1);
    for(int i = 0; i < 10; i++)
    {
        Animal *= list[i];
        p->makeSound();
 
    }
 
    for(int i = 0; i < 10; i++)
    {
        Animal *= list[i];
 
    }
}
cs

와 같이 수정을 해준다.

아까있던 if문들이 다 사라지고 훨신더 간결해졌는데 이렇게되면 makeSound를 어떻게부르냐.. 싶다

 

여기서 이제 나오는게 Virtual (가상함수) 이다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Animal{
protected:
    int age;
    int type;
public:
    Animal(int n) {
        age = n;
    }
    virtual void eat() {
        printf("...\n");
    }
    virtual void makeSound() {
        printf("???\n");
    }
};
cs

 

Animal 라는 다른 클래스들의 부모클래스에서 중복되는 이름들을 위해 만들어준 eat() makeSound() 함수 앞에

virtual 을 붙여주게되면

 

위 Main의 p->makeSound() 의 같은 경우에

p가 맨 처음 Tiger클래스를 하위클래스로 가지고 있기때문에 자동으로 Tiger 클래스의 makeSound()함수로 들어가게 해준다

 

 

이렇게해서 나오는 최종 코드로는

 

 

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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include <stdio.h>
 
class Animal{
protected:
    int age;
    int type;
public:
    Animal(int n) {
        age = n;
    }
    virtual void eat() {
        printf("...\n");
    }
    virtual void makeSound() {
        printf("???\n");
    }
};
 
 
class Elephant : public Animal{
    int totalTon;
 
public :
    Elephant(int n) : Animal(n){
        totalTon = 0;
    }
 
    void eat() {
        printf("이 코끼리가 %d그램 먹었습니다.\n", age*1);
        totalTon = totalTon + age*1;
    }
    void makeSound() {
        printf("뿌우 ~~\n");
    }
};
class Rabbit : public Animal{
    double totalGram;
public :
    Rabbit(int n)  : Animal(n){
        totalGram = 0;
    }
 
    void eat() {
        printf("이 토끼가 %f그램 먹었습니다.\n", age*0.8);
        totalGram = totalGram + age*0.8;
    }
    void makeSound() {
        printf("찍찍 ~~\n");
    }
};
class Tiger : public Animal{
    int totalRabbit;
 
public :
    Tiger(int n)  : Animal(n){
        totalRabbit = 0;
    }
 
    void eat() {
        printf("이 호랑이가 %d그램 먹었습니다.\n", age*5);
        totalRabbit = totalRabbit + age*5;
    }
    void makeSound() {
        printf("어흥 ~~~\n");
    }
}; 
 
int main()
{
 
    Animal *list[10];
 
    list[0= new Tiger(2);
    list[1= new Rabbit(3);
    list[2= new Rabbit(2);
    list[3= new Rabbit(5);
    list[4= new Elephant(1);
    list[5= new Tiger(2);
    list[6= new Elephant(7);
    list[7= new Rabbit(3);
    list[8= new Rabbit(9);
    list[9= new Tiger(1);
    for(int i = 0; i < 10; i++)
    {
        Animal *= list[i];
        p->makeSound();
 
    }
 
    for(int i = 0; i < 10; i++)
    {
        Animal *= list[i];
        p->eat();
    }
}
cs

 

 

 


 마지막으로 virtual void eat() 이런식으로 만들어 둔것들은 절대 호출될 일이 없기때문에..

 

굳이 printf("..."); 이런식으로 적어줄 필요가없고

1
2
virtual void eat() = 0;
virtual void makeSound() = 0;
cs

 

이런식으로 사용을 해주어도 되는데 이것을 pure virtual function (순수 가상 함수)

라고 부른다.

 

댓글