programming

Static binding vs Dynamic binding

sseram 2023. 7. 6. 23:08
반응형

컴파일 될 때 바인딩 되는지, 런타임에 바인딩 되는지에 따라 동작이 상이하게 달라진다.

그래서 무엇이 바인딩 되느냐? -> 각 클래스의 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을 사용하게 된다. 

 

반응형