본문 바로가기
Dev Language/C++

Is a, Has a 관계 & 상속

by 미티치 2016. 12. 23.

Is – aHas – a 관계

 Fruit 클래스에는 과일의 무게와 칼로리 열량을 저장할 수 있다. 그리고 Fruit 클래스를 상속받는 Banana 클래스에는 Fruit 클래스 멤버들을 상속받을 수 있으므로 바나나 무게와 칼로리 열량을 저장하는 멤버들을 가질 것이다. 또한 일반적으로 과일에는 적용되지 않고 바나나에만 적용되는 바나나 연구소 껍질 지수와 같은, 새 멤버들을 Banana 클래스에 추가할 수 있다. 파생 클래스에 새로운 기능도 추가할 수 있으므로 그 관계를 is-a-kind-of로 표시하는 것이 더 정확하겠지만, 흔히 is-a 관계라는 말을 사용한다.

가장 일반적인 public 상속은 has-a 관계를 나타내지 않는다. 예를 들어, 점심이 과일을 가질 수는 있지만 일반적으로 점심은 과일이 아니다. 따라서 점심에 과일을 포함시키려는 시도로 Fruit 클래스로부터 Lunch 클래스를 파생시키면 안 된다. 점심에 과일을 넣는 것은 Lunch 클래스의 한 데이터 멤버로 Fruit 객체를 포함시키는 것이 가장 쉬운 방법이다. 이것이 바로 has-a 관계이다.

 

 

 

상속

 

 프로그램이 파생 클래스의 객체를 생성할 때, 먼저 기초 클래스의 객체를 생성한다. 개념적으로 프로그램이 파생 클래스 생성자의 몸체 안으로 들어가기 전에, 기초 클래스 객체가 먼저 생성되어야 한다는 것을 의미한다. 따라서 C++에서는 멤버 초기자 리스트 문법을 사용한다.

 예를 들어, 기초 클래스 APlayer 를 파생한 BPlayer 파생 클래스가 있을 때, BPlayer 생성자에 해당하는 코드는 다음과 같다. 여기서 파생 클래스 생성자가 기초 클래스 생성자에게 매개변수 fn, ln, ht를 전달한다.

BPlayer :: BPlayer ( int r,  const char * fn, const string & ln, bool ht ) : APlayer (fn, ln, ht)
{          rating = r;
}

 만약 멤버 초기자 리스트를 생략하면 디폴트 기초 클래스 생성자를 사용한다. 앞의 코드에서 사용자가 : APlayer (fn, ln, ht) 부분을 생략하면, 내부적으로는 : APlayer () 가 실행될 것이다.

 반대로 파생 클래스의 객체가 수명을 다했을 때, 프로그램은 먼저 파생 클래스의 파괴자를 호출하고 그 다음 기초 클래스 파괴자를 호출한다.

 

-       기초 클래스 참조와 포인터가 파생 클래스 객체를 참조할 수 있다.

-       따라서 기초클래스 참조와 포인터를 매개변수로 사용하는 함수는, 기초 클래스 객체에도 사용할 수 있고 파생 클래스 객체에도 사용할 수 있다.

void Show(const BPlayer & rp) {             }

형식 매개변수 rp는 기초 클래스에 대한 참고이다. 따라서 rp는 기초 클래스 객체도 참조할 수 있고 파생 클래스 객체도 참조할 수 있다. 그래서 Show() 함수는 BPlayer 매개변수도 사용할 수 있고 APlayer 매개변수도 사용할 수 있다.

-       파생 클래스 참조나 포인터를 기초 클래스 참조나 포인터로 변환하는 것을 업캐스팅(upcasting)이라 한다. 따라서 Brass 클래스에서 파생된 BrassPlus 클래스에 대해서 다음과 같은 문법이 허용된다.
BrassPlus dilly(“Annie Dill”, 493222, 2000);
Brass * pb = &dilly;
Brass & rb = dilly;

-       기초 클래스 포인터나 참조를 파생 클래스 포인터나 참조로 변환하는 다운캐스팅(downcasting)은 업캐스팅과 다르게 명시적인 데이터 형 변환 없이는 허용되지 않는다.

 

 

Private 상속

 has-a 관계를 구현하는 수단으로 사용되는 방법. Public 상속에서는 기초 클래스의 public 메서드가 파생 클래스에서 public 메서드가 되지만, private 상속에서는 기초 클래스의 public 메서드가 파생 클래스의 private 메서드가 된다. , 파생 클래스가 기초 클래스의 인터페이스를 상속하지 않는다.

Class Student : private std :: string, private std :: valarray<double>
{                   };

-       기초 클래스의 public, protected 멤버가 p파생 클래스의 private 멤버가 된다.

-       클래스 안에 다른 클래스를 선언하는 containment ( has-a관계) , 객체를 이름이 있는 멤버 객체로 클래스에 추가하지만, private 상속은 객체를 이름이 없는 상속된 객체로 클래스에 추가한다. 이 두 가지 방법 모두 구현은 획득하지만 인터페이스는 획득하지 않는다. 두 접근 방식의 차이는 인터페이스가 아니라 구현에 영향을 준다.

-       다중 상속 가능

-       보통은 private 상속보다는 containment를 선호하지만, 상속을 사용하면 파생 클래스는 기초 클래스의 protected 멤버에 접근할 수 있고 또한 가상 함수를 재정의해야 할 필요가 있을 때 사용한다.

 

 

 

Protected 상속

 기초 클래스의 public 멤버와 protected 멤버가 파생 클래스의 protected 멤버가 된다.

Class Student : private std :: string, private std :: valarray<double>
{                   };

-       Private 상속과 Protected 상속의 주된 차이점 ?

 

'Dev Language > C++' 카테고리의 다른 글

C++로 DLL 만들기  (0) 2017.03.08
정적 결합과 동적 결합 & 가상함수  (0) 2016.12.23
참조 변수 & 복사 생성자  (1) 2016.12.06
if문과 switch문  (0) 2016.12.06
함수 오버로딩  (0) 2016.12.06