클래스가 다른 클래스에게 자신이 가지고 있는 멤버들을 물려주는 것을 상속이라고 한다.
상속을 하는 쪽과 상속을 받는 쪽을 각각 다음의 용어들로 정의한다.
| 상속 하는 쪽 | 상속 받는 쪽 |
|---|---|
| 상위 클래스 | 하위 클래스 |
| 기초(base) 클래스 | 유도(derived) 클래스 |
| 슈퍼(super) 클래스 | 서브(sub) 클래스 |
| 부모 클래스 | 자식 클래스 |
예를 들러, UnivStudent 클래스가 Student 클래스를 상속받을 때, 다음과 같은 형식으로 상속받는다.
#ifndef US_HPP
#define US_HPP
#include <iostream>
#include <cstring>
using namespace std;
//부모 클래스
class Person
{
private :
int age;
char name[50];
public :
Person(int myage, char *myname);
void WhatYourName() const;
void HowOldAreYou() const;
};
//자식 클래스
class UnivStudent : public Person //UnivStudent가 Person을 'public' 상속함
{
//부모 클래스로부터 물려받은 멤버에 더해 자신만의 독자적인 멤버를 추가로 선언한다.
private :
char major[50]; //전공과목
public :
UnivStudent(char *myname, int myage, char *mymajor);
void WhoAreYou() const;
};
#endif
상속은 다음과 같은 특성을 갖는다.
-
접근제어 지시자의 접근제한 기준은 객체가 아닌 클래스이기 때문에 부모 클래스에서 private으로 선언한 멤버는 자식 클래스에서 접근이 불가능하다.
- 따라서 자식 클래스에서 부모 클래스의 private 멤버에 접근하기 위해서는 부모 클래스로부터 상속받은 public 함수를 사용하는 우회적인 방법을 사용해야 한다.
- 이렇듯 정보의 은닉은 하나의 객체 안에서도 진행이 된다.
-
자식 클래스는 자신의 멤버 뿐만이 아니라 상속받은 멤버도 초기화하여야 한다.
- 이를 위하여 생성자를 호출할 때 이니셜라이저를 사용하여 부모의 생성자를 호출한다.
- 만약 부모의 생성자를 호출하지 않는 경우, 부모의 생성자 중 매개변수가 void인 생성자를 자동으로 호출한다 ( 없을 경우 error ).
- 구체적인 생성자 호출 순서는 아래와 같다.
- 자식 클래스 객체의 메모리 공간이 할당된다.
- 자식 클래스의 생성자가 호출된다 ( 실행은 아직 되지 않은 상태 ).
- 부모 클래스가 있는 지 확인 후, 있다면 부모 클래스의 생성자를 호출한다.
- 부모 클래스 생성자를 실행하여 부모의 멤버변수를 초기화한다.
- 자식 클래스 생성자를 실행하여 자식의 멤버변수를 초기화한다.
// 부모 클래스의 생성자
Person::Person(int myage, char *myname) : age(myage)
{
strcpy(name, myname);
}
// 자식 클래스의 생성자
UnivStudent::UnivStudent(char *myname, int myage, char *mymajor) : Person(myage, myname) // -> 이니셜라이저를 사용하여 부모의 생성자를 호출함
{
strcpy(major, mymajor);
}
-
자식 클래스의 객체가 소멸될 때에는, 자식 클래스의 소멸자가 실행되고 난 다음에 기초 클래스의 소멸자가 실행된다.
- 스택의 생성된 객체의 소멸 순서는 생성 순서와 반대이다.
-
접근제어 지시자는 멤버의 접근 범위를 제한하는 것 외에도 상속의 형태를 정의할 수 있다. 따라서 상속애는 public, protected, private 이렇게 3가지 형태의 상속이 있다.
- public 상속의 경우, private 멤버를 제외한 나머지(private 멤버는 자식에서 접근이 불가하므로) 그대로 상속한다.
- protected 상속의 경우, protected 보다 접근 범위가 넓은 멤버 ( 즉 public ) 의 접근 범위를 protected로 변환시켜 상속한다.
- private 상속의 경우, private 보다 접근 범위가 넓은 멤버의 접근 범위를 private으로 변환시켜 상속한다.
-
상속은 남용하지 않고 적절한 경우에만 사용되어야 한다. 상속을 사용하기 적합한 클래스와 클래스 사이 관계의 특징은 다음과 같다.
-
IS_A 관계.
- 예를 들어 컴퓨터 정보를 나타내는 Computer 클래스가 있고, 노트북 정보를 나타내는 Notebook 클래스가 있으면 둘은 IS_A 관계라 할 수 있다. 다음의 문장이 성립하기 때문이다.
노트북은 컴퓨터이다
또는
노트북은 컴퓨터의 일종이다.
- 예를 들어 컴퓨터 정보를 나타내는 Computer 클래스가 있고, 노트북 정보를 나타내는 Notebook 클래스가 있으면 둘은 IS_A 관계라 할 수 있다. 다음의 문장이 성립하기 때문이다.
-
HAS_A 관계.
- 에를 들어 경찰을 나타내는 Police 클래스가 있고, 총을 나타내는 Gun 클래스가 있을 때 다음의 문장이 성립하므로 HAS_A 관계라 할 수 있다.
경찰은 총을 가지고 있다.
- 에를 들어 경찰을 나타내는 Police 클래스가 있고, 총을 나타내는 Gun 클래스가 있을 때 다음의 문장이 성립하므로 HAS_A 관계라 할 수 있다.
-
다만 HAS_A 관계는 상속을 사용하기보다는 객체를 다른 객체의 멤버변수로 선언함으로서 표현하는 것이 일반적이다.
-
-
부모 클래스의 함수를 자식 클래스에서 오버로딩 할 수 있다.
-
부모 클래스의 함수를 자식 클래스에서 재정의 할 수 있다. 이를 함수 오버라이딩이라 한다.
-
부모 클래스의 포인터로 자식 포인터의 객체를 가리킬 수 있다.
-
하나의 객체가 동시에 복수의 객체를 상속받는 것이 가능하다. 이를 다중 상속이라고 한다.
참고자료