본문 바로가기

교육 노트/C# 강의

[C# 때려잡기] C# 강의 31. 가상함수, 정적 바인딩, 동적바인딩



class Weapon
{
public void Attack()
{
Console.WriteLine("무기로 공격!");
}
}
class Knife : Weapon
{
public void Attack()
{
Console.WriteLine("칼로 공격!");
}
}


출처: https://see-ro-e.tistory.com/133 [SeeRoE 프로그래밍 기록]

저번에 이런식으로 오버라이딩 했다.


여기서


이렇게 weapon을 다운캐스팅 하지 않고 그상태로 attack을 호출하게 되면



어택의 부모가 불리게된다.


namespace ConsoleApp4
{
class Weapon
{
public void Attack()
{
Console.WriteLine("무기로 공격!");
}
}
class Knife : Weapon
{
public void Attack()
{
Console.WriteLine("칼로 공격!");
}
}

class Program
{
static void Main(string[] args)
{
Weapon w = new Knife();
w.Attack();
}
}
}



이걸 해결하기 위해서 knife의 attack가 불리도록 downcasting을 해보자


((Knife)w).Attack();


잘나온다.


아 그러면 앞으로는 해당 무기가 무엇인지 언제나 파악하고 오버라이딩 함수를 쓸때마다 해당 무기에 맞게 다운캐스팅을 하여 함수를 호출해줘야하는것일까?

아니 그럼 에초에 오버라이딩은 왜있는거고 

그것보다 나는 웨폰은 생성한 적도 없는데 웨폰의 어택이 불리는건 이상하지않은가?


왜 웨폰의 어택이 불리는것일까?




1. 정적 바인딩 과 동적 바인딩


바인딩은 연결하는것이다.


클래스에서 함수는 메모리에 한번 올라간다고 했다.

메모리에 weapon과 knife의 attack이 올라가있다.


함수는 메모리에 올라가고 함수 포인터를 통하여 해당 함수에 접근하는데

그 함수포인터가 요함수 저함수 가르키는도록 하는것이 바인딩이다.



그리고 기존의 함수들은 정적 바인딩이다

이제 다들 알겠지만 동적은 런타임 정적은 컴파일 타임이다.

즉 저 함수가 연결되는 시점은 정적이다.


내가 weapon*로 만드는순간 저 웨폰포인터를 통해 불리는 모든 어택 함수는 정적으로 이미

weapon 의 attack으로 정해져버렸다


그래서 knife로 만들어도 저 attack이 불리는것이다

knife는 동적할당이므로 만드는 시점은 동적이기 때문이다


그래서 저 바인딩 동작이 attack에서는 동적으로 동작하도록 변경해야한다



2. 동적 바인딩 (dynamic binding) 와 가상함수

해결 방안은 간단하다


class Weapon
{
public virtual void Attack()
{
Console.WriteLine("무기로 공격!");
}
}
class Knife : Weapon
{
public override void Attack()
{
Console.WriteLine("칼로 공격!");
}
}

부모 함수명 앞에 virtual 이라는 키워드를 붙이고

자식함수 앞에 override 라는 키워드를 붙이면된다.





virtual 키워드는 컴파일러에게 요놈은 내가 런타임시간에 어떤함수를쓸지 결정해서 쓸께~ 라고 알려주는 역할을 한다.



따라서 동적할당을 하면 또 동적으로 함수가 바인딩이 된다.


그리고 virtual 키워드를 붙였기 때문에 해당 함수를 가상함수라고한다.

그냥 명칭이 그렇다



이제 함수를 사용해보자


namespace ConsoleApp4
{
class Weapon
{
public virtual void Attack()
{
Console.WriteLine("무기로 공격!");
}
}
class Knife : Weapon
{
public override void Attack()
{
Console.WriteLine("칼로 공격!");
}
}

class Program
{
static void Main(string[] args)
{
Weapon w = new Knife();
w.Attack();
}
}
}

와 형변환 필요없이 잘나온다!

이제 신경쓸필요없이 사용할수있게되었다.


또한 이러한 가상함수가 1개라도 있어야

해당 함수가 다형클래스가 된다. 실제 다형으로 사용할수 있게 되기때문같은데

암튼 따라서 다이나믹 캐스팅을 사용할려면 가상함수가 1개 이상 존재해야한다.




728x90