C++에서 바인딩(Binding)은 식별자(변수나 함수 이름)를 실제 메모리 주소로 연결하는 과정을 의미합니다. 모든 변수와 함수에 대해 바인딩이 수행되며, 특히 함수의 경우 컴파일러가 함수 호출을 올바른 함수 정의와 매칭시키는 작업을 말합니다. 이 바인딩은 컴파일 시점 또는 런타임 시점에 수행될 수 있으며, 각각 초기 바인딩과 후기 바인딩으로 구분됩니다.
초기 바인딩(Early Binding)이란?
초기 바인딩은 컴파일 타임 다형성(정적 다형성)이라고도 불립니다. 컴파일러가 컴파일 단계에서 함수 호출에 해당하는 주소를 직접 연결하므로 실행 속도가 빠르다는 장점이 있습니다. 대표적인 예로 함수 오버로딩(Function Overloading)과 연산자 오버로딩이 있습니다.
다만 초기 바인딩에서는 포인터의 선언된 타입을 기준으로 함수가 결정되기 때문에, 아래 예제처럼 파생 클래스 객체를 기반 클래스 포인터로 가리키더라도 기반 클래스의 함수가 호출되는 한계가 있습니다.
예제 코드
#include<iostream>
using namespace std;
class Base {
public:
void display() {
cout << "In Base class" << endl;
}
};
class Derived : public Base {
public:
void display() {
cout << "In Derived class" << endl;
}
};
int main(void) {
Base *base_pointer = new Derived;
base_pointer->display();
return 0;
}실행 결과
In Base class
포인터가 Derived 객체를 가리키고 있음에도 불구하고, 컴파일러가 포인터의 타입(Base*)을 기준으로 함수를 미리 결정했기 때문에 기반 클래스의 display()가 호출된 것을 확인할 수 있습니다.
후기 바인딩(Late Binding)이란?
후기 바인딩은 런타임 다형성(동적 다형성) 또는 동적 바인딩이라고 합니다. 이 방식에서는 컴파일러가 실행 중에 객체의 실제 타입을 식별하는 코드를 추가하고, 그 정보를 바탕으로 함수 호출을 올바른 함수 정의와 매칭합니다. 이는 가상 함수(virtual function)를 통해 구현됩니다.
함수 앞에 virtual 키워드를 붙이면, C++는 가상 함수 테이블(vtable)을 생성하여 런타임에 객체의 실제 타입에 맞는 함수를 동적으로 호출하게 됩니다.
예제 코드
#include<iostream>
using namespace std;
class Base {
public:
virtual void display() {
cout << "In Base class" << endl;
}
};
class Derived : public Base {
public:
void display() {
cout << "In Derived class" << endl;
}
};
int main() {
Base *base_pointer = new Derived;
base_pointer->display();
return 0;
}실행 결과
In Derived class
display() 함수를 virtual로 선언하기만 했는데, 이번에는 파생 클래스의 함수가 호출되었습니다. 런타임에 포인터가 실제로 가리키는 객체의 타입(Derived)을 확인하여 올바른 함수를 실행한 것입니다.
초기 바인딩 vs 후기 바인딩 비교
- 초기 바인딩: 컴파일 시점에 함수 결정 · 속도가 빠름 · 함수 오버로딩 등에 사용
- 후기 바인딩: 런타임에 함수 결정 · 유연성이 높음 · 가상 함수를 통해 구현 · 약간의 성능 오버헤드 존재
객체 지향 프로그래밍에서 다형성을 제대로 활용하려면 후기 바인딩의 원리를 이해하는 것이 필수적입니다. 상속 구조에서 기반 클래스 포인터나 참조를 통해 다양한 파생 클래스 객체를 다루고자 할 때는 반드시 virtual 키워드를 활용해야 의도한 대로 동작합니다.