[C/C++ 강좌] 89강. 다중 상속과 다이아몬드 문제
https://www.youtube.com/watch?v=32JMPbqcSe0&list=PLlJhQXcLQBJqywc5dweQ75GBRubzPxhAk&index=94
87강, 88강은 문제와 문제풀이 관련 이므로 생략
87강 : https://www.youtube.com/watch?v=SmFvPysbi6A&list=PLlJhQXcLQBJqywc5dweQ75GBRubzPxhAk&index=92
88강 : https://www.youtube.com/watch?v=Qibt0BAlmwA&list=PLlJhQXcLQBJqywc5dweQ75GBRubzPxhAk&index=93
1. 다이아몬드 문제
다중상속은 c++에서 지원하지만 기본적으로 지원되지 않는 언어들도있다. 그만 큼 문제가 많기 때문이다.
그리고 다중상속은 c++에서도 사용하지 않을 것을 권장한다.
우선 객체지향 관점에서도 문제가 생긴다.
#include <iostream>
using namespace std;
class Person {
public:
int age;
virtual ~Person() {}
void Eat() {
cout << "먹는다..." << endl;
}
};
class Student : public Person {
void Study() {
cout << "공부한다..." << endl;
}
};
class Worker : public Person {
void Work() {
cout << "일한다..." << endl;
}
};
class Researcher : public Student, public Worker { };
int main() {
Researcher r;
r.Student::age = 20;
}
위 코드는 아래 그림과 같은 형태로 상속되어 있다.
Student도 age가 있고 Workder에도 age가 있으므로 Researcher는 두 개의 나이(age)를 갖게 된다.
그런데 사람은 나이가 1개밖에 없어야한다. 학생(Student)으로서의 나이가 있고 직장인(Worker)의 나이가 따로 있다는 것은 현실에서 보면 이상한일이다. 그래서 객체지향 관점에서도보면 분명 이상해보인다.
그리고 인스턴스 생성할 때도 문제가 생긴다.
Person *p = new Researcher;
위와 같은 인스턴스를 생성할 때 Researcher는 Person은 Student를 통하는지 Worker를 통하는지도 모호하게 되어서 구문오류가 뜬다. 이러한 문제는 객체지향의 4대원리인 다형성에 문제가 생기기 때문에 다중 상속을 권장하지 않는다.
2. 가상 상속
다이아몬드 문제를 해결하기 위해 나온 방안이 가상 상속이다.
class Student: virtual public Person {
...
}
class Worker : virtual public Person {
...
}
Student와 Worker를 가상 상속으로 선언하면 Researcher은 Person클래스로부터 직접 상속을 받게 된다.
그러면 age도 1개만 존재하고 인스턴스도 정상적으로 생성이 가능하다.
가상상속의 한계
하지만 가상상속 조차도 한계가 있다. 예를들어 Student클래스와 Worker클래스가 Person클래스의 하나의 멤버를 동시에 오버라이딩을 하는 경우 Researcher에서 또 모호함이 발생한다.
이쯤되면 다중상속을 왜 만들었는지 의문이 생기지만 다중상속도 하나의 원칙만 지키면 사용할 수 있다.
'다중상속은 인터페이스로부터만 받는다'
3. 인터페이스
인터페이스 : 모든 메서드가 순수 가상 함수이고 (비정적)멤버 변수는 없는 클래스
추상 클래스 : 순수 가상 함수가 하나 이상 들어있는 클래스
다형적 클래스 : 가상 함수가 하나 이상 들어 있는 클래스
다음의 코드는 위의 코드들을 인터페이스화 시킨 코드이다.
#include <iostream>
using namespace std;
class IPerson {
public:
virtual ~IPerson() {}
virtual void Eat() = 0;
virtual int GetAge() = 0;
};
class IStudent : virtual public IPerson {
public:
virtual void Study() = 0;
};
class IWorker : virtual public IPerson {
public:
virtual void Work() = 0;
};
class Researcher : public IStudent, public IWorker {
public:
void Eat() {
cout << "먹는다..." << endl;
}
void Study() {
cout << "공부한다..." << endl;
}
void Work() {
cout << "일한다..." << endl;
}
int GetAge() {
return age;
}
int age;
};
int main() {
IPerson* r = new Researcher();
int age = r->GetAge();
r->Eat();
delete r;
}