(전체가 아니라 C#과 차이가 있는 부분을 중심으로 요약 정리)

상속을 이용한 클래스 구현

클래스 확장하기

C++에서 클래스를 정의할 때 컴파일러에게 기존 클래스를 상속(inherit), 파생(derive), 확장(extend) 한다고 선언할 수 있다. 이렇게 하면 새로 만들 클래스에 기존 클래스의 데이터 멤버와 메서드를 자동으로 가져올 수 있다. 이때 원본 클래스를 부모 클래스(베이스 클래스 또는 슈퍼 클래스(super class))라 부른다. 그러면 기존 클래스를 확장한 자식 클래스(child class) 또는 파생(derived class) 또는 서브 클래스(subclass)는 부모 클래스와 다른 부분만 구현하면 된다.

Base 클래스가 다음과 같이 생겼다고 하자.

class Base
{
  public:
    void someMethod();
  protected:
    int mProtectedInt;
  private:
    int mPrivateInt;
}

이제 Derived 클래스가 Base 클래스를 상속하도록 만들어 보자.

class Derived : public Base
{
  public:
    void someOtherMethod();
}

(이하 설명 생략)

클라이언트 입장에서 본 상속

다른 코드에서 볼 때 Derived 타입의 객체는 Base 타입의 객체이기도 하다. Derived는 Base를 상속했기 때문이다. 따라서 Base에 있는 public 메서드나 데이터 멤버 뿐만 아니라 Derived의 public 메서드와 데이터 멤버도 사용할 수 있다.

상속은 반드시 한 방향으로만 진행된다는 점에 주의한다. Derived 클래스 입장에서는 Base 클래스와의 관계가 상당히 명확하지만 Base 클래스를 정의하는 시점에서는 Derived 클래스의 존재를 알 수 없다.

어떤 객체를 포인터나 레퍼런스로 가리킬 때 그 객체를 선언한 클래스의 객체뿐만 아니라 그 클래스의 파생 클래스 객체도 가리킬 수 있다. 레퍼런스도 마찬가지다. 클라이언트는 기본적으로 Base에 있는 데이터 멤버나 메서드에 접근할 수 있지만 상속을 통해 Base에 적용되는 코드를 Derived에도 적용할 수 있다.

예컨대 다음과 같이 작성하면 타입이 맞지 않는 것처럼 보이지만 정상적으로 컴파일 된다.

Base* base = new Derived();  // Derived 객체를 생성해서 Base 포인터에 저장한다.

그런데 Base 포인터로 Derived 클래스의 메서드를 호출할 수는 없다. 다음과 같이 작성하면 컴파일 에러가 발생한다.

base->someOtherMethod();

객체의 실제 타입이 Derived이고 실제로 someOtherMethod()가 정의돼 있지만 컴파일러는 여전히 이 객체의 타입이 someOtherMethod()가 없는 Base로 알고 있기 때문이다.

파생 클래스 입장에서 본 상속

파생 클래스를 작성하는 방법은 일반 클래스와 기본적으로 같다. 파생 클래스의 메서드와 데이터 멤버도 일반 클래스처럼 정의한다.