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 *p = list[i];
if(p->getType() == ELEPHANT) {
Elephant *q = (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 *p = list[i];
if(p->getType() == ELEPHANT) {
Elephant *q = (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 *p = list[i];
p->makeSound();
}
for(int i = 0; i < 10; i++)
{
Animal *p = 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 *p = list[i];
p->makeSound();
}
for(int i = 0; i < 10; i++)
{
Animal *p = list[i];
p->eat();
}
}
|
cs |
마지막으로 virtual void eat() 이런식으로 만들어 둔것들은 절대 호출될 일이 없기때문에..
굳이 printf("..."); 이런식으로 적어줄 필요가없고
1
2
|
virtual void eat() = 0;
virtual void makeSound() = 0;
|
cs |
이런식으로 사용을 해주어도 되는데 이것을 pure virtual function (순수 가상 함수)
라고 부른다.
'Dev > [C++]개념정리' 카테고리의 다른 글
[개탱][C++][상속][inheritance][사원관리 프로그램][행렬][자료구조][수정필요] (0) | 2018.01.02 |
---|---|
[개탱][C++][상속][inheritance][수정필요] (0) | 2018.01.02 |
[개탱][C++][shallow copy][deep copy] (0) | 2018.01.02 |
[개탱][C++][Operator Overloading][Operator][Overloading][복소수][complexNumber][2] (0) | 2018.01.02 |
[개탱][C++][Operator Overloading][Operator][Overloading][복소수][complexNumber][1] (0) | 2018.01.02 |