static : 정적
dynamic : 동적
정적은 컴파일 타임에 일어나는 것을 의미하고
동적은 런 타임에 일어나는 것을 의미합니다.
그러니까 각각
컴파일 타임에 일어나는 바인딩,
런 타임에 일어나는 바인딩인 것이죠.
부모 클래스 Base와
자식 클래스 Derived가 있고
둘이 오버라이딩 된 메서드 func를 갖고 있다고 합시다.
C++의 상속 관계에서
다운캐스팅, 업캐스팅이 가능합니다.
다운캐스팅은 부모 클래스 -> 자식 클래스
업캐스팅은 자식 클래스 -> 부모 클래스
Base* Ptr = new Derived;
이렇게 되면 Derived 객체를 Base*가 가리키고 있으므로 업캐스팅인 겁니다.
여기서
Ptr->func();
를 하게 되면
Base::func
Derived::func
중 뭐가 호출될까요?
Base::func가 호출됩니다.
왜냐하면
Base*는 Base 타입, Derived 타입의 객체를 가리킬 수 있는데
이 때문에 컴파일러는 Ptr이 가리키는 객체의 실 타입이 무엇인지 알 수 없는 것이죠.
이때는 그냥 알 거 없이 Base::func를 실행합니다.
이게 정적 바인딩에요. 컴파일 타임에 Base쪽 메서드를 실행하겠다고 결정하는 것.
그런데 문제는 Derived에서 오버라이딩 됐다면 대다수의 경우는 무조건 Derived::func를 실행해야 한다는 겁니다.
그런데 아까 컴파일러는 Ptr이 가리키는 실 타입을 모른다고 했죠?(컴파일 타임엔 알 수가 없다 !)
따라서 런 타임에 동적으로 바인딩을 해야해요.
그 방법이 virtual 키워드를 붙여 가상 함수로 선언하는 것입니다.
클래스가 가상 함수를 하나라도 가지고 있으면 그 클래스에는 '가상 함수 테이블'이 생성됩니다. (vtable, vftable)
이 가상 함수 테이블에는 실행할 함수(Derived::func)의 주소를 가지고 있습니다.
그 주소를 참조해서 동적으로 바인딩을 하는 것이죠.
그리고 클래스 필드에 가상 함수 테이블이 위치한 주소를 알기 위한
내부적으로 포인터가 하나 추가됩니다.