728x90

지금까지 다루었던 상속은 단일 상속이었다. 이번에는 다중으로 클래스를 상속받는 방법에 대해서 알아본다. 

 

Multiple Inheritance (다중 상속)

말 그대로 Base Class가 두 개 이상이 되는 것을 의미한다. 내용은 간단하니 바로 코드를 보면서 알아본다. 

 

Base 클래스가 두 개일 경우 생성자와 소멸자는 어떤 순서로 호출이 되는지를 보여주는 코드이다. 

#include <iostream>

class Lion
{
public:
	Lion()
	{
		std::cout << "Lion constructor\n";
	}
	virtual ~Lion()
	{
		std::cout << "Lion destructor\n";
	}
private:
	double lionData;
};

class Tiger
{
public:
	Tiger()
	{
		std::cout << "Tiger constructor\n";
	}
	virtual ~Tiger()
	{
		std::cout << "Tiger destructor\n";
	}
private:
	double tigerData;
};

class Liger : public Tiger, public Lion
{
public:
	Liger()
	{
		std::cout << "Liger constructor\n";
	}
	~Liger()
	{
		std::cout << "Liger destructor\n";
	}
private:
	double ligerData;
};

int main()
{
	Liger liger();
}

Tiger와 Lion을 Base클래스로 가지는 Derived클래스 Liger는 상속의 순서를 public Tiger, public Lion으로 지정을 해주었다. 그럴 경우 아래와 같이 생성자와 소멸자가 호출이 되게 된다. 

사진과 같이 앞에 있는 Tiger의 생성자가 호출이 되고 그다음 Lion 그다음 Liger의 생성자가 호출이 되는 것을 확인할 수 있다. 만약 Lion을 앞에 써주었을 경우에는 Lion의 생성자가 먼저 호출이 될 것을 유추할 수 있다. 

 

 

다중 상속의 경우 해당 클래스의 사이즈는 어떤지 알아보자. 위 코드에서 상속받은 두 클래스의 사이즈를 각각 알아보면 Lion클래스 사이는 1개의 double형 멤버 변수 8바이트와 virtual함수로 인한 virtual table을 가리키는 포인터 8바이트 총 16바이트이다. Tiger클래스 또한 double형 멤버 변수 1개와 virtual 멤버 함수로 인한 virtual table을 가리키는 포인터 8바이트 총 16바이트이다. Liger클래스에 double형 멤버 변수가 존재하니 통 40바이트이다. 

Liger object 메모리 구조

그러하면 궁금증이 두 개의 클래스를 상속을 받아 virtual table을 가리키는 포인터 두 개 존재하게 되는데 어떻게 작용하는지 궁금할 수 있다. 그것에 대해 알아보자. 

 

클래스 자체의 코드는 생략하고 main함수의 코드만 가지고 예를 들어본다. ㅇ

int main()
{
    Tiger* polyTiger = Liger();
    delete polyTiger;
    return 0;
}

지난 포스트에서 Base클래스 포인터 형으로 Derived 객체를 생성할 수 있다고 배웠다. 위 예는 두 개의 Base 클래스에서 Tiger 클래스 포인터를 이용하여 Liger객체를 생성한 코드이다. 이 경우 아래 사진과 같이 Tiger 오브젝트에 관한 메모리는 보이지 않고 Liger와 Tiger만 접근이 가능하다. 그러하기 때문에 Tiger객체에 있는 포인터가 Liger Virtual Table을 가리키게 된다. 

 

다음 예제로 Lion 클래스형 포인터로 Liger 객체를 생성하였을 때 접근 가능한 메모리와 어떠한 포인터가 Virtual Table을 가리키게 되는지를 알아본다. 

int main()
{
    Lion* polyLion = Liger();
    delete polyLion;
    return 0;
}

Lion클래스 포인터로 Liger객체를 선언했다. 아래는 해당 내용의 메모리와 Virtual Table을 어떻게 가리키게 되는지 표현하는 그림이다. 

 

 

마지막으로 Liger클래스 포인터로 Liger객체를 선언할 경우이다. 

int main()
{
    Liger* polyLiger = Liger();
    delete polyLiger;
    return 0;
}

 

위 경우는 모든 Base클래스 오브젝트가 접근이 가능하고 두 Base클래스의 포인터가 모두 Liger Virtual Table을 가리키게 된다. 

+ Recent posts