가상 상속 (Virtual Inheritance)
Programming/C++ 2012. 8. 22. 21:13 |※ 다중 상속을 하였을 때 함수 호출관계의 모호함은 다른 상황에서도 발생할 수 있다.
#include <iostream>
using namespace std;
class Base
{
public:
Base()
{
cout<<"Base Constructor"<<endl;
}
void SimpleFunc()
{
cout<<"BaseOne"<<endl;
}
};
class MiddleDerived_1 :public Base
{
public:
MiddleDerived_1()
:Base()
{
cout<<"MiddleDerived_1 Constructor"<<endl;
}
void MiddleFunc_1()
{
SimpleFunc();
cout<<"Middlederived_1"<<endl;
}
};
class MiddleDerived_2 :public Base
{
public:
MiddleDerived_2()
:Base()
{
cout<<"MiddleDerived_2 Constructor"<<endl;
}
void MiddleFunc_2()
{
SimpleFunc();
cout<<"Middlederived_2"<<endl;
}
};
class LastDerived :public MiddleDerived_1, public MiddleDerived_2
{
public:
LastDerived()
:MiddleDerived_1(), MiddleDerived_2()
{
cout<<"LastDerived Constructor"<<endl;
}
void ComplexFunc()
{
MiddleFunc_1();
MiddleFunc_2();
MiddleDerived_2::SimpleFunc(); //이렇게 명시해주지않으면 에러발생.
} //왜냐면 어느클래스에서 쓸 것인지 모르기 때문.
}; //현재 Base Class는 두개이다.
int main(void)
{
cout<<"객체생성 전 ... "<<endl;
LastDerived ldr;
cout<<"객체생성 후 ... "<<endl;
ldr.ComplexFunc();
return 0;
}
위 예제는 LastDerived 클래스가 Base 클래스를 간접적으로 두 번 상속하였다. 다중상속의 모호한 상황이다!!
이렇듯 하나의 객체 내에 두 개의 Base 클래스 멤버가 존재하기 때문에 complexFunc 함수 내에서 이름만 가지고 SimpleFunc 함수를 호출할 수는 없다.
이 경우에는 다음과 같이, 어느 클래스를 통해서 간접 상속한 Base 클래스의 멤버함수를 호출할 것인지 명시해야 한다.
ex) MiddleDerived_1::SimpleFunc();
// MiddleDerived_1 클래스가 상속한 Base 클래스의 SimpleFunc 함수호출을 명령!
그런데 이러한 상황에서, Base 클래스의 멤버가 LastDerived 객체에 하나씩만 존재하는 것이 타당한 경우가 대부분이다.
즉, Base 클래스를 딱 한번만 상속하게끔 하는 것이 더 현실적인 해결책이 될 수 있다.
그리고 이를 위한 문법이 바로 "가상 상속" 이다.
ex) class MiddleDerived_1 :virtual public Base
{ };
ex) class MiddleDerived_2 :virtual public Base
{ };
#include <iostream>
using namespace std;
class Base
{
public:
Base()
{
cout<<"Base Constructor"<<endl;
}
void SimpleFunc()
{
cout<<"BaseOne"<<endl;
}
};
class MiddleDerived_1 :virtual public Base
{
public:
MiddleDerived_1()
:Base()
{
cout<<"MiddleDerived_1 Constructor"<<endl;
}
void MiddleFunc_1()
{
SimpleFunc();
cout<<"Middlederived_1"<<endl;
}
};
class MiddleDerived_2 : virtual public Base
{
public:
MiddleDerived_2()
:Base()
{
cout<<"MiddleDerived_2 Constructor"<<endl;
}
void MiddleFunc_2()
{
SimpleFunc();
cout<<"Middlederived_2"<<endl;
}
};
class LastDerived :public MiddleDerived_1, public MiddleDerived_2
{
public:
LastDerived()
:MiddleDerived_1(), MiddleDerived_2()
{
cout<<"LastDerived Constructor"<<endl;
}
void ComplexFunc()
{
MiddleFunc_1();
MiddleFunc_2();
SimpleFunc(); //virtual inheritance(가상 상속) 을 해주었기때문에
} //Base Class는 하나로 오버라이딩되어 명시해주지 않아도 된다.
}; //왜냐면, Base Class가 하나밖에 없기 때문.
int main(void)
{
cout<<"객체생성 전 ... "<<endl;
LastDerived ldr;
cout<<"객체생성 후 ... "<<endl;
ldr.ComplexFunc();
return 0;
}
이렇듯, 가상으로 Base 클래스를 상속하는 두 클래스를 다음과 같이 다중으로 상속하게 되면,
class LastDerived : public MiddleDerived_1, public MiddleDerived_2
{ };
LastDerived 객체 내에는 MiddleDerived_1 클래스와 MiddleDerived_2 클래스가 동시에 상속하는 Base 클래스의 멤버가 하나씩만 존재하게 된다.!!
- 위 예제에서 SimpleFunc 함수를 이름만 가지고 호출할 수 있을 것이다.
그리고 예제의 실행결과를 보면 실제로 Base 클래스의 생성자가 한번만 호출되는 것을 확인할 수 있다.
만약에 가상 상속을 하지 않는다면, Base 클래스의 생성자는 두 번 호출된다.
'Programming > C++' 카테고리의 다른 글
단항 연산자의 오버로딩 (0) | 2012.08.27 |
---|---|
연산자 오버로딩 (Operator Overloading) (0) | 2012.08.25 |
다중 상속(Multiple Inheritance) (0) | 2012.08.22 |
가상함수의 동작원리와 가상함수 테이블 (0) | 2012.08.22 |
객체(Instance) 와 멤버함수(Method) 의 관계 (0) | 2012.08.22 |