[C++] 가상(Virtual)의 원리

dd_ddong·2022년 8월 2일
0

c++

목록 보기
29/38

멤버함수의 위치

클래스를 struct와 전역 함수로 풀어서 나타내면 다음과 같다.

struct Data
{
	int data;
    void (*ShowData)(Data*);
    void (*Add)(Data*, int);
}

void ShowData(Data* this) { cout << "data : "<< this->data<< endl; }
void Add(Data* this, int num) { this->data += num; }

int main()
{
	Data obj1 = {15, ShowData, Add};
    Data obj2 = {10, ShowData, Add};
    
    obj1.Add(&obj1, 5);
    obj1.ShowData(&obj1);
}

class도 똑같다. 같은 class형식의 여러 객체가 생성된다해도 멤버함수는 하나만 존재하고 이를 각각의 함수 포인터가 가리키는 형태가 된다.

하지만 함수호출 시 각 객체로 정보가 전달되고(this) 이를 기반으로 함수를 실행하므로 논리적으론 객체안에 멤버함수가 존재한다고 할 수 있다.

가상함수의 동작원리

하지만 virtual 선언된 멤버함수가 하나라도 있을시에는 그 구조가 바뀐다.

멤버함수를 Key로 갖고 그 위치를 Value로 가지는 가상함수 테이블이 class마다 생기게 된다. 멤버함수가 호출된다하면 virtual table에서 함수의 주소를 탐색/추출한 다음 그 주소의 함수를 호출한다.

위오 같은 클래스 AAA, BBB가 존재한다고 하면 virtual table은

AAA class

BBB class

이때 오버라이드한 Func1의 경우 BBB class의 virtual table에서 AAA::Func1은 삭제되고 BBB::Func1만 남게 된다.
따라서 BBB객체에서 Fuc1을 호출하기 위해 virtual table을 탐색하면 BBB의 Func1밖에 없으므로 BBB::Fun1이 호출된다.

다중 상속

여러 개의 class를 상속받는 것
class Derived :public FirstBase, public SecondBase { }

다중상속의 모호성

base1에 Fun1이 있고 base2에도 Fun1가 있다고 가정했을 때
이 둘을 다중상속하는 Derived의 객체를 통해 Fun1을 호출한다했을 때 어떤 base의 Fun1을 호출할지 모호해진다.

더 모호한 경우


위와 같은 상속구조를 가지고 있는 LastDerived 객체가 있다하면

같이 Base의 멤버가 2개 존재하게 된다.

따라서 이를 해결하기 위해 virtual 상속을 한다.

class Derived : virtual public Base { }

virtual 상속으로 base를 상속하게 되면 Base의 멤버를 하나만 포함하게 된다.

0개의 댓글