함수 오버로딩 : 함수 이름이 똑같으면 컴파일러가 어떤 함수를 호출할지 모르는데 인자가 다르다면 컴파일러는 함수를 호출할때 들어가는 인자 들을 보고 호출해야하는 함수를 구분 할 수가 있음.



함수 오버라이딩 : 부모 클래스 포인터에 자식 클래스를 할당 시킬 때 만약 부모 클래스에 Speak() 함수가 있고 자식 클래스에 Speak() 함수가 있을 때 부모 포인터지만 할당 시킨 객체는 자식 이므로 자식 클래스의 Speak() 함수가 호출될거라고 생각하지만 실제로는 부모 클래스의 함수가 호출 됨.

그 이유는 정적 바인딩 때문인데 컴파일러는 class에 함수가 있으면 해당 멤버 함수를 어딘가에 만들어 놓고 객체가 자신의 멤버 함수를 호출 할때 자신의 객체를 인자로 보냄.


즉, 클래스 객체마다 함수를 가지고 있는 것이 아니라 메모리에 한번만 저장되고 함수를 호출할떄마다 해당 메모리에 저장된 함수를 호출하는 것임. 그 어딘가는 코드 영역 or 텍스트 영역일 것임.

다시 돌아와서 자식 객체를 할당한 부모 포인터의 Speak 함수를 호출 할때, Speak 함수에 전달되는 객체는 부모 클래스 이기 떄문에 부모의 Speak 함수가 호출 되는것. 하지만 우리가 원하는 것은 부모 멤버 함수가 아니라 자식 멤버 함수임. 이걸 하기 위해서는 동적 바인딩을 알아야됨.


부모 클래스에 멤버 함수를 virtual 키워드를 사용해서 가상 함수로 만들게 되면 가상 테이블이라는게 만들어짐. 부모 클래스의 Speak() 함수가 가상 함수가 되면 해당 함수의 주소는 부모 클래스의 가상 테이블에 저장됨.

또한 해당 부모 클래스의 자식 클래스도 똑같은 Speak() 함수가 있으면 부모 클래스의 Speak() 함수가 virtual 이기 때문에 해당 자식 멤버 함수도 가상 테이블에 저장 됨.

이렇게 가상 테이블이 어딘가에 생성이됨. 이제 이걸 어떻게 사용하냐인데 우리가 객체를 만들게 됐을때 해당 객체가 동적 바인딩이 된 객체라면 생성될때 해당 가상 테이블을 가르키는 포인터를 하나 달고나옴.

그럼 이제 우리가 부모 클래스 포인터에 자식 클래스를 할당했을 때 Speak 함수를 호출하면


정적 바인딩에서는 부모 클래스의 함수를 호출 했지만 동적 바인딩에서는 객체가 가르키고있는 가상 테이블의 함수를 호출하게 되니까 부모 객체 포인터라도 할당된 자식 객체의 함수가 호출되는 거임. 왜냐? 생성된 자식 객체는 가상 테이블을 가지고있으니까 그 테이블의 함수를 호출하면 되는거니까

즉, 한 부모 에게서 상속 받은 함수가 있는데 이걸 다른 각각의 자식들이 자신에 맞게 같은 함수라도 동작이 다르게 다양하게 사용하는 것을 다형성 이라고 하는 것.


정적 바인딩 : 컴파일 타임에 어떤 함수가 호출이 될지 판단이 되는것 ( 속도 빠름 )

동적 바인딩 : 런타임일때 어떤 함수가 호출이 될지 판단 하는 것.  ( 속도 느림 )