컴파일 될 때 바인딩 되는지, 런타임에 바인딩 되는지에 따라 동작이 상이하게 달라진다.
그래서 무엇이 바인딩 되느냐? -> 각 클래스의 method.
기본적으로 다형성(polymorphism)과 관련된 개념. 객체 지향 언어들이 이 다형성을 위하여 보통 dynamic binding을 많이 사용한다고 한다.
#include <iostream>
using namespace std;
class myClass {
public:
virtual void someFunc() {
cout << "1" << endl;
}
};
class derived : public myClass {
public:
void someFunc() {
cout << "2" << endl;
}
};
int main() {
myClass* A = new myClass();
A->someFunc(); // 어떤 것이 호출?
myClass* B = new derived();
B->someFunc(); // 어떤 것이 호출?
return 0;
}
A는 myClass를 새롭게 생성했고, B는 derived를 새롭게 생성했다.
myClass의 someFunc은 1을 출력하고, derived의 someFunc은 2를 출력한다.
위의 코드를 실행하면 어떤 결과가 나올까?
A->someFunc() 을 하면 당연히 '1' 이 출력될 것이다.
하지만 B->someFunc()을 하면 B의 type이 derived가 아닌 myClass임에도 불구하고 '2'가 출력된다.
C++를 오래 사용해본 사람은 당연하다고 생각할 것이다. 그렇다면 이 당연한 것이 dynamic binding때문에 일어난다는 사실도 같이 알고 갔으면 좋겠다.
분명히 B의 자료형은 myClass이고, myClass의 someFunc() 은 '1' 을 출력하게끔 정의해 두었다. 하지만 컴파일 할 때에 컴파일러는 B의 someFunc() 을 해석 할 때 바로 myClass의 someFunc으로 가게끔 함수의 주소를 바인딩하지 않는다. 그 대신, virtual table에 해당 정보를 적어 두고(앞에 virtual이라는 표시가 있다면), runtime때 본인의 실제 함수를 따라가게 된다.
물론 virtual이라는 keyword를 사용하지 않으면, static binding으로 진행되게 되어, 컴파일 타임에 A, B 가 부를 함수를 결정해 버린다.
#include <iostream>
using namespace std;
class myClass {
public:
void someFunc() {
cout << "1" << endl;
}
};
class derived : public myClass {
public:
void someFunc() {
cout << "2" << endl;
}
};
int main() {
myClass* A = new myClass();
A->someFunc(); // 어떤 것이 호출?
myClass* B = new derived();
B->someFunc(); // 어떤 것이 호출?
return 0;
}
이러다 보니, 같은 자료형이라도 다른 동작을 할 수 있는 polymorphism을 쉽게 구현할 수가 있게 된다.
OOP를 공부하다 보면 자주 나오는 아래 코드같은 것들 말이다.
#include <iostream>
#include <vector>
using namespace std;
class animal {
public:
virtual void hi() {
cout << "--" << endl;
}
};
class dog : public animal {
public:
void hi() override {
cout << "멍" << endl;
}
};
class cat : public animal {
public:
void hi() override {
cout << "야옹" << endl;
}
};
int main() {
vector<animal*> animals;
animals.push_back(new dog());
animals.push_back(new cat());
for (auto&& i : animals) {
i->hi();
}
return 0;
}
dynamic binding을 사용하기 때문에, 위와 같은 결과가 나온다고 알아두면 좋을 것 같다.
참고로, C#에서는 이렇게 사용한다고 한다.
public class A{
public void someFunc();
}
// dynamic binding
public class B : public A
{
public void override someFunc();
}
// static binding
public class C : public A
{
public void new someFunc();
}
1. static binding
- 컴파일 시간에 binding을 수행된다.
- 컴파일 시간에 정확하게 알 수 있는 함수를 호출한다.
- 미리 binding 되므로, 성능이 좋고 실행 속도가 빠르다.
2. dynamic binding
- 런타임에 binding을 수행한다.
- 런타임 중 실제 함수로 해석하여, 해당 함수를 호출한다.
- 런타임 시에 binding되므로, static binding 보다는 효율이 떨어진다.
이렇게 차이를 나눠두긴 했지만.. 사실 OOP 를 사용하여 프로그래밍을 한다면, 엥간하면 dynamic binding으로 사용하는 게 여러모로 쓸모가 많으니, dynamic binding을 사용하게 된다.