Computer >> 컴퓨터 >  >> 프로그래밍 >> C++

C++에서 기본 인수와 가상 함수의 상호작용 완벽 이해하기

C++ 기본 인수와 가상 함수

C++에서 기본 인수(default argument)가상 함수(virtual function)를 함께 사용하면 의외의 동작이 발생할 수 있습니다. 그 이유는 두 기능이 처리되는 시점이 다르기 때문입니다. 핵심 개념을 쉽게 이해할 수 있도록 샘플 프로그램을 통해 살펴보겠습니다.

예제 코드

#include<iostream>
using namespace std;
class B {
    public:
        virtual void s(int a = 0) {
            cout<<" In Base \n";
        }
};
class D: public B {
    public:
        virtual void s(int a) {
            cout<<"In Derived, a="<<a;
        }
};
int main(void) {
    D d; // D 클래스의 객체
    B *b = &d; // d를 가리키는 B* 타입의 포인터
    b->s();
    return 0;
}

실행 결과

In Derived, a = 0

결과 분석

실행 결과를 보면, 파생 클래스의 s() 함수가 호출되었지만, 기본 클래스 s()에 정의된 기본값이 사용된 것을 확인할 수 있습니다. 포인터의 타입은 B*인데도 파생 클래스의 함수가 실행된 점이 흥미롭습니다.

이러한 결과가 나타나는 이유는 다음과 같습니다.

  • 기본 인수는 함수 시그니처에 포함되지 않습니다. 따라서 기본 클래스와 파생 클래스의 s()는 동일한 시그니처로 간주되며, 파생 클래스의 s()가 기본 클래스의 s()를 오버라이드하게 됩니다.
  • 기본값은 컴파일 타임에 결정됩니다. 컴파일러가 함수 호출에서 인수가 누락된 것을 발견하면, 포인터의 정적 타입(B)을 기준으로 기본값 a = 0을 대입합니다.
  • 가상 함수는 런타임에 바인딩됩니다. 실제 호출되는 함수는 객체의 동적 타입(D)에 따라 결정되므로, 런타임에는 파생 클래스의 s()가 호출됩니다.

정리하면, 위 프로그램에서는 인수 값 a = 0이 컴파일 타임에 대입되고, 런타임에는 파생 클래스의 s()가 호출되는 것입니다. C++에서는 기본 인수는 정적 바인딩으로, 가상 함수는 동적 바인딩으로 처리되기 때문에 이처럼 직관에 어긋나는 결과가 발생할 수 있습니다. 따라서 가상 함수를 설계할 때는 기본 인수 사용에 주의하는 것이 좋으며, 필요하다면 기본 클래스와 파생 클래스 모두에 동일한 기본값을 명시하는 것이 안전합니다.