삶의 공유
[C++] 정적 결합, 동적 결합 본문
Summary)
정적 결합
: 가리키고 있는 타입이 아니라 스스로, 변수(객체)의 타입만 보고 어떤 함수로 갈지를 결정 한 것이다. 이렇게 객체의 타입만 보고 가는 것을 정적 결합이라고 한다. 다시 얘기하면 컴파일 타임에 어떤 것을 호출할지 이미 결정하는 것을 정적 결합
예 ) 함수 오버로딩
동적 결합
런타임 바인딩, 즉 런타임 도중에 타입이 결정되는 것을 동적 바인딩이라고 한다.
예 ) 함수 오버라이딩
오버로딩에 대해 알아보자.
#include <iostream>
using namespace std;
class A
{
public:
int num;
};
class B : public A
{
};
A operator+(const A& x, const A& y)
{
A a;
a.num = x.num + y.num;
return a;
}
B operator+(const B& x, const B& y) // 오버로딩 규칙에 의해서 이 함수로 적용이 된다.(좀더 구체적으로 기술이 되어 있기 때문에.)
{
B b;
b.num = x.num * y.num;
return b;
}
int main()
{
B a0, a1;
a0.num = 10;
a1.num = 20;
A a2 = a0 + a1;
cout << a2.num << endl;
}
이 예제의 실행 결과는 200이다.
이유는 오버로딩 규칙에 의해서 좀더 구체적으로 기술되어 있는 B operator+(const B& x, const B& y) 구문으로 적용 되기 떄문이다
여기까지는 크게 어렵지 않다.
하지만 이 예제를 살펴 보자
#include <iostream>
using namespace std;
class A
{
public:
int num;
};
class B : public A
{
};
A operator+(const A& x, const A& y)
{
A a;
a.num = x.num + y.num;
return a;
}
B operator+(const B& x, const B& y) // 오버로딩 규칙에 의해서 이 함수로 적용이 된다.(좀더 구체적으로 기술이 되어 있기 때문에.)
{
B b;
b.num = x.num * y.num;
return b;
}
int main()
{
B b0, b1;
b0.num = 10;
b1.num = 20;
A& a0 = b0;
A& a1 = b1;
A a2 = a0 + a1;
cout << a2.num << endl;
}
실행 결과는 30이다.
a0 = b0 / a1 = b1 으로 되어 있으나, 가리키고 있는 타입이 아니라 스스로, 변수(객체)의 타입만 보고 어떤 함수로 갈지를 결정 한 것이다.
이렇게 객체의 타입만 보고 가는 것을 정적 결합이라고 한다.
다시 얘기하면 컴파일 타임에 어떤 것을 호출할지 이미 결정하는 것을 정적 결합
즉, 함수 오버로딩은 정적 결합이다.
※ 오버로딩은 디버거를 통해서라도 런타임 도중에 변경이 불가능하다.
이번엔 오버라이딩에 대해서 알아보자
#include <iostream>
using namespace std;
class Animal
{
public:
virtual void eat() const
{
cout << "냠" << endl;
}
};
class Cat : public Animal
{
public:
virtual void eat() const override
{
cout << "냥" << endl;
}
};
class Dog : public Animal
{
public:
virtual void eat() const override
{
cout << "냥" << endl;
}
};
int main()
{
Animal* a = new Dog();
a->eat(); // 가리키고 있는 객체의 함수를 호출함
// 런타임 도중에 매번 가리키고 있는 함수를 찾음 (런타임 바인딩임.)
}
오버라이딩의 경우는 런타임 도중에 매번 가리키고 있는 함수를 찾음 (런타임 바인딩임.)
런타임 바인딩, 즉 런타딤 도중에 타입이 결정되는 것을 동적 바인딩이라고 한다.
※ virtual키워드르 붙이면 동적 바인딩이다. 만약 virtual을 붙이지 않으면 정적 바인딩이다.
※ 런타임 도중에 변경이 가능하다 (디버거를 통해서)
위의 Animal Class에서 포인터 변수를 넣고 사이즈를 컴파일 해보면 8byte의 사이즈가 된다. 이것은 virtual키워드를 넣으면 포인터로 추측되는 무언가가 있다고 추측을 할 수 있다.
즉 virtual 키워드가 있으면, 이 가상 함수를 가르키는 포인터가 있는것이다.
예제를 보면,
#include <iostream>
using namespace std;
class Animal
{
public:
int* p;
virtual void eat() const
{
cout << "냠" << endl;
}
virtual void foo()
{
cout << "foo " << endl;
}
};
class Cat : public Animal
{
public:
virtual void eat() const override
{
cout << "냥" << endl;
}
};
class Dog : public Animal
{
public:
virtual void eat() const override
{
cout << "냥" << endl;
}
};
int main()
{
Dog d;
Animal* animal = new Cat; // 부모가 자식을 가르킬때는 가상함수 메카니즘에 의해 가상함수 테이블을 통해 런타임 도중에 함수를 찾는다
animal->eat(); // 런타임 도중에 최적의 함수인 오버라이딩에 의해 "냥"을 출력한다.
}
'Programing언어 > C++' 카테고리의 다른 글
[C++] C++와 표준 라이브러리 초단기 속성코스(리터럴(literal) & 변수) (0) | 2021.01.28 |
---|---|
[C++] C++ 기초(주석, 전처리 지시자, main()함수, I/O Stream) (0) | 2021.01.26 |
[C++] 클래스 템플릿 (0) | 2021.01.20 |
[C++] 템플릿(Template) - 2 (0) | 2021.01.19 |
[C++] 가상 함수(상속) (0) | 2021.01.18 |