0. 가상 함수란?
- 파생 클래스에서 '재정의'(오버라이딩) 할 것으로 기대되는 함수에 붙이는 키워드, virtual
1. 가상화 조건
- UpCasting 된 포인터 변수에서 virtual로 정의된 함수를 부르게 된다면 실제 인스턴스에 맞는 함수를 불러줌
- 동적 바인딩이라고도 한다.
- 런타임에 실제 불러야 할 함수를 가상함수 테이블에서 찾아 함수를 불러주는 것
#include <iostream>
class Parent
{
public:
virtual void PrintMyName()
{
std::cout << "Parent" << std::endl;
}
};
class Child : public Parent
{
public:
virtual void PrintMyName()
{
std::cout << "Child" << std::endl;
}
};
int main()
{
Parent P;
Child C;
Parent* p = &P; //본인의 자료형에 맞는 인스턴스를 갖는 경우
p->PrintMyName();
p = &C; //이 상황을 UpCasting이라 할 수 있음, Child는 Parent의 자식이기 때문에 부모 포인터로도 자식을 가리킬 수 있음
p->PrintMyName();
return 0;
}
2. 가상함수 테이블
- 클래스 내 virtual 키워드가 붙은 함수가 하나라도 있다면 그 클래스는 가상함수 테이블이라는 것을 가지게 된다.
- virtual이라는 키워드가 붙은 만큼 숨겨 놓은 포인터를 만드는 거다. 그 포인터는 virtual 키워드가 붙은 함수의 주소를 가리키게 된다.
- 오버라이딩 된 함수는 각각 다른 주소를 가질 것이고 그 주소를 숨긴 포인터가 가리키게 된다. 이 때 파생 클래스 입장에선 새로운 포인터를 만드는 것이 아니고 기존 부모가 물고 있던 포인터의 주소를 바꾸는 방식이다.
- 실제 virtual로 정의된 함수를 부르게 되면 가상함수 테이블에서 그 함수의 주소를 가지고 있을 것이라 기대되는 포인터로부터 주소를 얻어와 부르게 된다.
- virtual을 붙인 것만으로 그 class는 포인터 크기(4byte 혹은 8byte)만큼 크기가 커지고 그 함수를 호출할 때 가상함수를 뒤져봐야 하는 부하가 걸릴 것이다.
3. 추상 클래스
- 순수 가상 함수를 하나라도 포함하고 있다면 추상 클래스이다.
- 추상 클래스는 인스턴스화 될 수 없다.
- 순수 가상 함수란 함수의 구현부 대신 = 0; 으로 대신한 함수를 의미한다.
- 추상 클래스도 포인터나 래퍼런스로서 활용될 수 있다.
#include <iostream>
class Parent
{
public:
virtual void PrintMyName() = 0;
};
class Child1 : public Parent
{
public:
virtual void PrintMyName()
{
std::cout << "Child1" << std::endl;
}
};
class Child2 : public Parent
{
public:
virtual void PrintMyName()
{
std::cout << "Child2" << std::endl;
}
};
int main()
{
//Parent P; //error
Parent* P1 = new Child1;
Child2 C2;
Parent& P2 = C2;
P1->PrintMyName();
P2.PrintMyName();
return 0;
}
4. 인터페이스
- 순수 가상 함수로만 구성된 클래스 혹은 구조체
- 인터페이스를 상속받는 클래스들은 공통의 함수를 구현하길 기대함
- 접두어로 I를 붙이기로 약속이 되어 있음
- C++의 정식 문법은 아니고 클래스와 순수 가상 함수의 특성을 적절히 조합하여 인터페이스를 흉내냄
- 인터페이스의 정의상으론 멤버 변수가 있으면 안됨
- 추상 클래스와 인터페이스의 경계선이 모호한 것이 현실.
5. 가상 소멸자
- UpCasting된 포인터 변수가 소멸할 때 본인 인스턴스의 소멸자를 찾아 부르기 위함(상속관계에 있다면 인스턴스를 상위계층의 호출자도 모두 부름)
- 위 예제에서도 virtual이 붙은 소멸자가 없기 때문에 Child 본인의 소멸자를 부르지 못하고 Parent의 소멸자를 불렀을 것
'C++ > 키워드 정리' 카테고리의 다른 글
키워드 정리 [15] - SOLID (2) | 2023.12.01 |
---|---|
키워드 정리 [14] - RTTI (1) | 2023.12.01 |
키워드 정리 [12] - 클래스 (4) | 2023.12.01 |
키워드 정리 [11] - OOP (1) | 2023.12.01 |
키워드 정리 [10] - Template (0) | 2023.12.01 |