본문 바로가기
C++/기초(두들낙서)

[C++] 다중상속

by Meaning_ 2022. 7. 13.
728x90
반응형

C++에서의 다중상속의 문제점에 대해서 알아보자. 다중상속했을 때의 문제를 다이아몬드 문제라고 한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
using namespace std;
 
 
struct Person {
 
    int age;
    virtual ~Person() {};
    void Eat() {
        cout << "먹는다.." << endl;
    }
};
 
struct Student :Person {
    void Study() {
        cout << "공부한다.." << endl;
    }
};
 
struct Worker :Person {
 
    void Work() {
        cout << "일한다..." << endl;
    }
};
 
struct Researcher :Student, Worker {
 
 
};
 
 
int main() {
 
    
    Researcher r;
    r.age = 20;
    
    
}
cs

r.age에 접근하려고 하면 에러가 뜬다. 단 r.Student::age  r.Worker::age를 하면 접근이 가능한다. 논리적으로 좀 이상하다.

age는 하나여야 하는데 두개이기 때문이다. 

 

이런 다중상속의 해결책이 가상상속이다. 

 원래는 Student와 Worker가 Person으로 부터 상속을 받고 Researcher가 Student와 Person으로 부터 상속을 받았다면

가상상속을 받았다면 Student와 Worker가 가상이기에 Researcher가 직접  Person으로 부터 상속받게 된다.

 

 

가상상속은 상속받을 때 virtual 키워드를 붙여주면 된다. 

 

이러면 이제 Researcher는 Person으로 부터 바로 상속받아오는 것(나머지는 가상상속)이기에 r.age가 가능해진다.

 

그럼에도 오버라이딩을 하게 되면 (예를 들어 Person의 Eat함수) 가상상속을 한다하더라도  또 에러가 뜨는 문제점이 생긴다. Person의 Eat함수를 Student와 Worker모두에서 오버라이딩 했을 때 r.Eat()을 하게 되면 Student와 Worker 중 어디서 받아와야하는지 모호해지는 문제가 생기면서 에러가 뜬다. 

 

그래서 약속이 하나 있다.

 

"다중 상속은 인터페이스로부터만 받는다." (자바와 C#도 마찬가지)

 

인터페이스 

모든 메서드가 순수가상함수이고 멤버변수는 없는 클래스이다!

 

추상클래스: 순수 가상함수가 하나이상 들어 있는 클래스

다형적 클래스: 가상함수가 하나이상 들어 있는 클래스 

 

그리고 다중상속 시 인터페이스 일때도 가상상속을 사용해야 한다. 

인터페이스를 쓸때는 앞에 I를 붙여줘야 한다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
using namespace std;
 
 
struct IPerson {
 
    
    virtual ~IPerson() {};
    virtual void Eat() = 0;
};
 
struct IStudent : virtual IPerson {
    virtual void Study() = 0;
};
 
struct IWorker :virtual IPerson {
 
    virtual void Work() = 0;
};
 
struct Researcher :IStudent, IWorker {
 
    int age;
 
    void Eat() {
 
        cout << "먹는다" << endl;
    }
 
    void Study() {
        cout << "공부한다." << endl;
        
    }
 
    void Work() {
 
        cout << "일한다." << endl;
    }
 
};
 
 
int main() {
 
    
    
}
cs

 

 

이렇게 인터페이스를 선언해주면 오버라이딩 할 때도 순수가상함수이기에 실체가 없게 된다. 그래서 

모호한게 없게 된다. 아까 오버라이딩 얘기하면서 Eat함수 얘기를 했는데 

어차피 Eat함수가 순수가상함수이고 얘를 Student와 Worker로 가상상속시키면 사실상 Researcher는 Person의 Eat함수를 받아오게 될 것이다. 그리고 순수가상함수이기에 모호함도 없다. 

 

 

정사각형 - 직사각형 문제 

부모 클래스로부터 특정 함수를 상속받기 싫으면 delete 써주면 됨

 

 

정사각형 클래스에서 가로 길이를 바꾸는 함수를 상속받게 되면 정사각형이 아니게 된다. 이럴 때 delete 키워드를 통해 상속받아오지 않을 수 있다. 

728x90
반응형

댓글