클래스가 다른 클래스에게 자신이 가지고 있는 멤버들을 물려주는 것을 상속이라고 한다.

상속을 하는 쪽과 상속을 받는 쪽을 각각 다음의 용어들로 정의한다.

상속 하는 쪽상속 받는 쪽
상위 클래스하위 클래스
기초(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
 

상속은 다음과 같은 특성을 갖는다.

  1. 접근제어 지시자접근제한 기준은 객체가 아닌 클래스이기 때문에 부모 클래스에서 private으로 선언한 멤버는 자식 클래스에서 접근이 불가능하다.

    • 따라서 자식 클래스에서 부모 클래스의 private 멤버에 접근하기 위해서는 부모 클래스로부터 상속받은 public 함수를 사용하는 우회적인 방법을 사용해야 한다.
    • 이렇듯 정보의 은닉은 하나의 객체 안에서도 진행이 된다.
  2. 자식 클래스는 자신의 멤버 뿐만이 아니라 상속받은 멤버도 초기화하여야 한다.

    • 이를 위하여 생성자를 호출할 때 이니셜라이저를 사용하여 부모의 생성자를 호출한다.
    • 만약 부모의 생성자를 호출하지 않는 경우, 부모의 생성자 중 매개변수가 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);
}
 
  1. 자식 클래스의 객체가 소멸될 때에는, 자식 클래스의 소멸자가 실행되고 난 다음에 기초 클래스의 소멸자가 실행된다.

    • 스택의 생성된 객체의 소멸 순서는 생성 순서와 반대이다.
  2. 접근제어 지시자는 멤버의 접근 범위를 제한하는 것 외에도 상속의 형태를 정의할 수 있다. 따라서 상속애는 public, protected, private 이렇게 3가지 형태의 상속이 있다.

    • public 상속의 경우, private 멤버를 제외한 나머지(private 멤버는 자식에서 접근이 불가하므로) 그대로 상속한다.
    • protected 상속의 경우, protected 보다 접근 범위가 넓은 멤버 ( 즉 public ) 의 접근 범위를 protected로 변환시켜 상속한다.
    • private 상속의 경우, private 보다 접근 범위가 넓은 멤버의 접근 범위를 private으로 변환시켜 상속한다.
  3. 상속은 남용하지 않고 적절한 경우에만 사용되어야 한다. 상속을 사용하기 적합한 클래스와 클래스 사이 관계의 특징은 다음과 같다.

    • IS_A 관계.

      • 예를 들어 컴퓨터 정보를 나타내는 Computer 클래스가 있고, 노트북 정보를 나타내는 Notebook 클래스가 있으면 둘은 IS_A 관계라 할 수 있다. 다음의 문장이 성립하기 때문이다.
        노트북은 컴퓨터이다
        또는
        노트북은 컴퓨터의 일종이다.
    • HAS_A 관계.

      • 에를 들어 경찰을 나타내는 Police 클래스가 있고, 총을 나타내는 Gun 클래스가 있을 때 다음의 문장이 성립하므로 HAS_A 관계라 할 수 있다.
        경찰은 총을 가지고 있다.
    • 다만 HAS_A 관계는 상속을 사용하기보다는 객체를 다른 객체의 멤버변수로 선언함으로서 표현하는 것이 일반적이다.

  4. 부모 클래스의 함수를 자식 클래스에서 오버로딩 할 수 있다.

  5. 부모 클래스의 함수를 자식 클래스에서 재정의 할 수 있다. 이를 함수 오버라이딩이라 한다.

  6. 부모 클래스의 포인터로 자식 포인터의 객체를 가리킬 수 있다.

    • 그러나 컴파일러는 포인터 연산의 가능성 여부를 판단할 때, 실제 가리키는 객체의 자료형이 아닌, 포인터의 자료형을 기준으로 판단한다.
      • 따라서 부모 클래스의 포인터로 자식 포인터를 가리킬 경우 부모 포인터에서 정의되지 않은 함수를 사용할 수 없다 ( 이를 가상 함수를 통해 극복할 수 있다 ) .
      • 부모 클래스의 함수를 자식 클래스가 오버라이딩 한 경우, 가리키는 포인터의 자료형 클래스에서 선언된 함수가 호출된다.
      • 상술한 모든 특성은 참조자를 사용한 참조에도 모두 적용된다.
  7. 하나의 객체가 동시에 복수의 객체를 상속받는 것이 가능하다. 이를 다중 상속이라고 한다.


참고자료

윤성우의_열혈_cpp_프로그래밍