본문 바로가기

Programming/C / C++

[C++] 오버라이딩의 특징과 정적/동적 바인딩 (Overriding & Static / Dynamic Binding)

 virtual 특성의 상속  
 앞서 우리는 오버라이딩이란 무엇인지 알아 보았다. 그 중 virtual 이라는 키워드를 잠깐 알아 봤는데, 한가지 빼먹은 것이 있었다. 바로 오버라이딩에서의 virtual의 특징은 그것의 특성도 상속된다는 것이다. 
  위의 소스코드에서 BBB 클래스가 상속하고 있는 AAA 클래스의 Virtual void fct함수가 B클래스의 fct 함수에 의해서 오버라이딩 되어 지고 있다. 이 경우 오버라이딩을 하는 BBB 클래스의 fct 함수도 자동으로 virtual 키워드가 들어가게 된다. (명시적으로 써주나 안써주나 똑같지만, 코드의 가독성을 위해 써주는 것이 좋다. )
 C클래스도 마찬가지이다.아래와 같이 써주자. 
이것을 실행하면 어떤 결과를 출력하느냐? 앞서 오버라이팅 포스팅 부분에서도 언급했듯이 아래와 같은 결과를 출력하는것을 알 수 있다.

 만약 BBB,CCC 클래스가 없다고 가정할 경우를 생각해보자. AAA클래스만 있다고 하면, virtual은 의미를 가지지 않는다. virtual이라는 키워드는 오버라이딩 관계에 의해 상속되어질때만 의미를 지니기 때문이다. 

 정적/동적 바인딩  
 이번에는 정적 바인딩(Static Binding) 동적 바인딩 (Dynamic Binding)이 무엇인지 알아 보기 전에 바인딩(Binding)이란 무엇인지 알아 보자. 바인딩이란 프로그램 소스에 쓰인 각종 내부 요소, 이름, 식별자들에 대해 값 혹은 속성을 확정하는 과정을 일컫는 말이다.  이 과정이 빌드 중에 이루어지면 정적 바인딩이라고 하고, 실행 중에 이루어지면 동적 바인딩이라고 한다. 
 그럼 한번 예를 들어 보자 아래와 같이 A,B,C가 상속관계에 있고 abc라는 함수가 virtual로 선언되어 있다고 하자. 
 만약 메인 함수에서 다음과 같이 코딩을 했다고 해보자.
 객체 포인터 선언에 '어떤것'이 무엇인지 알아야 어떤것이 호출되는지 알수 있다. 포인터에 따라서 호출되는 함수가 결정되는 것이 아니라, 그 포인터가 가리키는 객체에 따라서 호출되는 함수가 결정된다는 것이 바로 동적 바인딩(Dynamic Binding)이다. 즉, 실제로 대상에 따라서 호출되는 함수가 상황에 따라 달라지는 것을 의미한다. 
 그럼 정적바인딩이란 무엇인가 ? 다음과 같은 선언이 있다고 해보자. 
 이 선언 부분에서 데이터 타입이 int로 정해지는 것과 그 타입의 변수명이 static_binding으로 정해지는 것이 바로 정적 바인딩(Static Binding) 이다. 

 C++의 가상 함수의 바인딩은 문서상으로는 동적 바인딩으로 되어 있으나, 구현상으로는 런타임 성능을 높이기 위해 정적 바인딩을 쓰고 있다. 즉, 컴파일중에 아예 가상 함수 테이블을 파생 클래스에 맞게 바꿈으로써, 겉보기에는 파생 클래스 타입에서 오버라이드한 가상 함수를 호출하는 것처럼 보이게 만드는 것이다. 

 오버라이딩된 함수 호출하기  
 : 오버라이딩된 함수를 호출하는 방법은 간단하다. 소스코드를 보면 한눈에 알아 볼 수 있다.
 위와 같이 fct함수를 그냥 호출 하는 것이 아니라, 16번째 줄처럼 명시적으로 정의가 선언되어 있는 클래스를 범위 지정 연산자로 지정해 주는 것이다. 이 AAA::fct() 코드부분의 의미는 "AAA클래스에 있는 fct 함수를 호출하라" 이다.

 순수 가상 함수와 추상래스  
 우선 가상함수에 대해서 복습해보자. 가상 함수(Virtual Function)는 파생 클래스가 안전하게 재정의할 수 있는 함수이다. 만약 상속 관계가 아니라면 가상 함수를 선언할 필요가 없으므로 가상 함수는 상속 계층내에서만 의미가 있으며 파생 클래스에게 재정의 기회를 주기 위해 존재하는 것이라고 할 수 있다. 
 하지만 이 가상 함수를 반드시 재정의해야만 하는 것은 아니다. 기반 클래스의 동작을 그대로 쓰고 싶으면 단순히 상속만 받고 변경할 필요가 있을 때만 재정의하면 된다. Base 클래스가 가상 함수를 만드는 이유는 혹시라도 재정의하고 포인터로 호출할 때를 대비한 것이다. 가상 함수는 재정의해도 되는 함수이지 반드시 재정의해야 하는 함수는 아닌 것이다. 
 그럼 순수 가상 함수는 어떤가? 순수 가상 함수(Pure Virtual Function)는 파생 클래스에서 반드시 재정의해야 하는 함수이다. 순수 가상 함수는 일반적으로 함수의 동작을 정의하는 본체를 가지지 않으며 따라서 이 상태에서는 호출할 수 없다. 본체가 없다는 뜻으로 함수 선언부의 끝에 =0이라는 표기를 하는데 이는 함수만 있고 코드는 비어 있다는 뜻이다. 아래와 같이 클래스 단에서 선언한다.
 또 이런 클래스(하나이상 가상함수를 지닌 클래스)를 추상 클래스(Abstract Class) 라고 일컫는다. 추상클래스는 완전한 클래스가 아니므로 객체화 될 수 없다.