1. 동적결합(Dynamic Binding)의 개념
프로그램이 실행 중일 때, 어떤 함수나 메서드를 호출할 때 실제로 어떤 코드를 실행할지를 결정하는 것
- 즉, 함수 호출이 어떤 객체나 클래스의 실제 버전을 호출할지를 런타임(runtime) 시점에 결정하는 것
- 주로 객체 지향 프로그래밍에서 다형성을 구현하는 데 사용됨
1) '프로그램 실행 중'에 객체의 실제 타입을 고려
2) 해당 타입에 맞는 함수나 메서드를 호출
- 이를 통해 서로 다른 객체가 동일한 함수 또는 메서드를 호출하더라도, 각 객체의 고유한 동작을 수행할 수 있음
2) c++에서 동적 결합을 구현하는 두 가지 주요 메커니즘
2-1. 가상함수 (virtual functions)
- 함수 앞에 virtual 키워드를 사용
- 가상 함수는 기본형 클래스에서 선언되고 파생 클래스(derived class)에서 재정의(override)할 수 있는 함수
- 가상 함수를 사용하면 런타임 시에 객체의 실제 타입에 따라 올바른 함수 버전이 호출됨
class Shape {
public:
virtual void draw() {
// 기본 구현 }
};
class Circle : public Shape {
public:
void draw() override {}
};
2-2. 가상테이블 (virtual table)
- 가상 함수를 사용할 때, C++ 컴파일러는 객체에 대한 가상 함수 포인터 테이블을 생성함
- 테이블은 가상 함수의 주소를 저장하고, 실제 함수 호출 시에 이 테이블을 참조하여 올바른 함수를 호출함
void drawShape(Shape* shape) {
shape->draw(); // 동적 결합
}
int main() {
Circle circle;
Square square;
drawShape(&circle); // Circle 클래스의 draw()가 호출됨
drawShape(&square); // Square 클래스의 draw()가 호출됨
return 0;
}
구체적인 예제로 동적 결합 이해하기
기초형 클래스의 pointer으로 구성된 포인터 array를 선언
→ 해당 array에 기초형 클래스 Time뿐 아니라, 상속 클래스인 NewTime의 주소값도 저장됨
→ array의 각 원소에 대해 virtual 메서드인 show()를 실행시켜줌
(show 실행될 때마다, 어떤 class 타입인지 실시간으로 판단해스 해당 타입에 대응되는 virtual 메서드를 실행시킴)
time.h
#include<iostream>
using namespace std;
#ifndef FIRE_C_TIME_H
#define FIRE_C_TIME_H
class Time{
private:
int hours;
int mins;
public:
Time();
Time(int, int);
/* virtual 통해 가상 메소드 선언 */
virtual void show(); //가상메소드
virtual ~Time(); //파괴자 역시 가상 메소드로 선언
int getHour(){return hours;}
int getMins(){return mins;}
Time operator*(int n);
friend Time operator*(int, Time&);
};
class NewTime : public Time {
private:
int day;
public:
NewTime(); //생성자
NewTime(int, int, int); //생성
void show();
};
#endif //FIRE_C_TIME_H
time_func.cpp
#include "time.h"
Time::Time(){
hours = 0;
mins = 0;}
Time::Time(int h, int m){
hours = h;
mins = m;}
void Time::show(){
cout << hours << "시간 " << mins << "분" << endl;}
Time::~Time(){}
NewTime::NewTime() : Time(){
day = 0;
}
NewTime::NewTime(int h, int m, int d) : Time(h, m) {
day = d;
}
void NewTime::show(){
cout << day << "일 " << getHour() << "시간 " << getMins() << "분" << endl;
}
main.cpp
#include "time.h"
#include "time_func.cpp"
const int MAX = 3;
int main(){
Time* times[MAX]; //기초형 Time 클래스의 포인터들이 저장된 배열
//이곳에 Time 기초형 클래스의 포인터도, NewTime 상속 클래스의 포인터도 담김
int day;
int hours;
int mins;
for (int i = 0; i < MAX; i++) {
cout << i + 1 << "번째 원소를 정의합니다." << endl;
cout << "시간을 입력하십시오." << endl;
cin >> hours;
cout << "분을 입력하십시오." << endl;
cin >> mins;
char check;
cout << "일 정보가 있다면 1, 없다면 0을 입력하십시오." << endl;
cin >> check;
if (check == '0')
times[i] = new Time(hours, mins);
else {
cout << "일을 입력하십시오." << endl;
cin >> day;
times[i] = new NewTime(hours, mins, day);
}
}
for (int i = 0; i < MAX; i++){
cout << i+1 << "번째 정보입니다." <<endl;
times[i]->show();
//show를 virtual로 선언했기 때문에,
//times: time의 pointer 배열이지만
//Times이면 Time의 show()가, NewTime이면 NewTime의 show()가 실행됨
}
for (int i = 0; i < MAX; i++){
delete times[i]; //delete의 경우 time형에 대한 delete만 이루어짐
//NewTime 객체의 경우 제대로 delete되지 않음
//이를 위해 파괴자 역시 virtual로 선언해야 함
}
return 0;}
'개발 > c++' 카테고리의 다른 글
[c++] const / 초기화 리스트!! (0) | 2023.09.24 |
---|---|
[c++] 서로 다른 & (참조자/주소반환) (0) | 2023.09.24 |
[c++] virtual 통한 가상 메서드 선언, public 함수 다형 상속 (0) | 2023.09.10 |
[c++] 클래스 상속 (0) | 2023.09.10 |
[c++] friend (feat. 연산자 오버로딩 응용) (0) | 2023.09.10 |