본문 바로가기
C#

[C#기초] 가상함수/ 동적바인딩,정적바인딩

by Meaning_ 2021. 8. 14.
728x90
반응형

가상함수를 설명하기 위해 축구 빅클럽을 예를 들어 설명해보겠습니다.

유럽에는 축구 빅클럽이 여러개 있는데 빅클럽을 부모 클래스로, 맨체스터시티와 파리 생제르망을 자식 클래스로 두겠습니다.

 

 

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
namespace Football
{
    class BigClub
    {
        public void Info()
        {
            Console.WriteLine("BigClub.info");
        }
    }
    class ManCity:BigClub
    {
        public void Info()
        {
            Console.WriteLine("ManCity.info");
        }
    }
    class Paris : BigClub
    {
        public void Info()
        {
            Console.WriteLine("Paris.info");
        }
    }
    class Program
    {
        static void ShowInfo(BigClub club)
        {
            club.Info();
        }
 
        static void Main(string[] args)
        {
            BigClub big = new BigClub();
            ManCity man = new ManCity();
            Paris paris = new Paris();
            ShowInfo(big);
            ShowInfo(man);
            ShowInfo(paris);
 
        }
    }
}
 
cs

 

 

그러면 답이 3개 다 BigClub.info로 나옵니다.

우리가 원하는 답은

BigClub.info

ManCity.info

Paris.info

인데 왜 그럴까요?

 

정적바인딩


1
2
3
4
 static void ShowInfo(BigClub club)
        {
            club.Info();
        }
cs

ShowInfo함수를 자세히 살펴보겠습니다.

일반함수는 ShowInfo함수에서 정적바인딩 되기 때문에 BigClub의 info함수가 호출되는 것으로 이미 결정납니다.

정적바인딩은 실행파일을 만들 때 어떤 함수를 호출할 때 미리 결정나는 것을 의미합니다. 

BigClub에 들어올 수 있는게 맨시티, 파리생제르망이 있는데 이것을 고려하지 않고 실행파일을 만들기 전에 데이터타입을 Bigclub으로 정하는 것이죠! 

 

 

일반메소드


그러면 가상함수를 알아보기 전에 가상함수와 구별되는 일반메소드의 차이점을 알아보겠습니다. 

 

그릇의 데이터타입에 의해 호출되는 것이 일반메소드 입니다.

 

이해가 잘 안될 수 있어서 한가지 예를 더 들어드리겠습니다.
메인메서드를 아래와 같이 바꿔보겠습니다. 

 

1
2
3
4
5
6
7
8
9
static void Main(string[] args)
{
            BigClub big = new BigClub();
            ManCity man = new ManCity();
            Paris paris = new Paris();
            BigClub mancity = new ManCity();
            mancity.Info();
            man.Info();
}
cs

 

 

 

이러면 Bigclub 객체를 그릇으로 가진 mancity는 Bigclub.info가 나오지만, ManCity를 객체로 가진 man은 ManCity.info가 나옵니다. 이것이 그릇의 데이터타입에 의해 호출된다는 것입니다!

 

 

 

가상메소드


만약 답을

BigClub.info

ManCity.info

Paris.info

로 바꾸고 싶으면 가상함수를 이용해야합니다. 

 

 

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
namespace Football
{
    class BigClub
    {
        public virtual void Info()
        {
            Console.WriteLine("BigClub.info");
        }
    }
    class ManCity:BigClub
    {
        public override void Info()
        {
            Console.WriteLine("ManCity.info");
        }
    }
    class Paris : BigClub
    {
        public override void Info()
        {
            Console.WriteLine("Paris.info");
        }
    }
    class Program
    {
        static void ShowInfo(BigClub club)
        {
            club.Info();
        }
 
        static void Main(string[] args)
        {
            BigClub big = new BigClub();
            ManCity man = new ManCity();
            Paris paris = new Paris();
            ShowInfo(big);
            ShowInfo(man);
            ShowInfo(paris);
 
        }
    }
}
 
cs

 

 

 public virtual void Info()

        {

            Console.WriteLine("BigClub.info");

        }

 

public override void Info()

        {

            Console.WriteLine("ManCity.info");

        }

 

virtual과 override를 사용해서 우리가 원하는 답을 만들어낼 수 있습니다!

 

 

가상함수 테이블 


가상함수가 있으면 가상함수 테이블이 만들어집니다

위 코드들에서 Player메소드를 빅클럽 클래스와 파리생제르망 클래스에 추가하고, Info메소드는 빅클럽 클래스와 맨시티 클래스에만 남겨두겠습니다. 

 

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
 
namespace Football
{
    class BigClub
    {
        public virtual void Info()
        {
            Console.WriteLine("BigClub.info");
        }
        public virtual void Player()
        {
            Console.WriteLine("BigClub.player");
        }
    }
    class ManCity:BigClub
    {
        public override void Info()
        {
            Console.WriteLine("ManCity.info");
        }
    }
    class Paris : BigClub
    {
        public override void Player()
        {
            Console.WriteLine("Paris.player");
        }
    }
    class Program
    {
        static void ShowInfo(BigClub club)
        {
            club.Info();
        }
 
        static void PlayerInfo(BigClub club)
        {
            club.Player();
        }
        static void Main(string[] args)
        {
            BigClub big = new BigClub();
            ManCity man = new ManCity();
            Paris paris = new Paris();
            ShowInfo(big);
            ShowInfo(man);
            ShowInfo(paris);
            PlayerInfo(big);
            PlayerInfo(man);
            PlayerInfo(paris);
 
        }
    }
}
cs
 

 

각 클래스의 가상함수 테이블을 살펴보겠습니다

 

BigClub virtual function Table

0:BigClub::info()

1:BigClub::display()

 

ManCity virtual funcion Table

 

0: ManCity::info() --> Info함수 주소값 가짐

1:ManCity::display() -->Player 함수는 만들지 않아서 부모의 주소값으로 들어감 

 

Paris virtual fuction Table

 

0: BigClub::info();

1: Paris:display();

 

 

만약, ShowInfo에 매개변수로 bigclub 객체가 들어온다면 가상함수 테이블에 의해

 

bigclub.virtualTable[0]()이 호출된다고 보시면 됩니다!

 

 

이런 원리로 작동하기에 ShowInfo(paris) 는 BigClub.info가 나오는 것이고, PlayerInfo(man)에 BigClub.player가 나오는 것입니다. 

 

 

동적바인딩 

 


가상함수를 만들면 정적바인딩이 불가능해지는데, 가상함수를 만들면 동적바인딩이 됩니다. 

virtual메소드를 BigClub클래스에 쓰게 되면 ShowInfo나 PlayerInfo의 매개변수에 BigClub에서 유도된 타입, 즉 자식 클래스들이 다 들어올 수 있기에 어떤객체가 정확히 들어오는지 모릅니다.

즉, 동적바인딩은 어느 데이터타입의 함수를 호출할지 결정을 유보하는 것이라 생각하시면 됩니다!

정적바인딩과 달리 실행파일을 만들면서 어떤함수를 호출할지 결정됩니다. 미리 결정되는 것이 아닙니다. 

728x90
반응형

'C#' 카테고리의 다른 글

[C# 기초] 다형성/상속  (0) 2021.07.27
[C#기초] 복사 생성자/ static  (0) 2021.07.27
[C#기초] 클래스와 구조체의 차이  (0) 2021.07.21
[C#기초] setter/getter 함수  (0) 2021.07.19
[C#기초] 참조  (0) 2021.07.19

댓글