본문 바로가기
책 정리/Effective C++ 3rd

항목 34. 인터페이스 상속과 구현 상속의 차이를 제대로 파악하고 구별하자

by ocean20 2020. 3. 9.

클래스 설계입장에서 다음과 같이 상속받고 싶게한다.

1. 멤버함수의 인터페이스(선언)만을 상속

2. 선언, 구현, 그리고 오버라이딩(재정의)까지 가능하게

3. 선언, 구현만 상속 가능하게

 

class shape{
public:
  virtual void draw() const = 0;  // 1. 순수 가상함수
  virtual void error(const std::string& msg); // 2. 비순수 가상함수
  int objectID() const;  // 3. 비가상함수
…
};

class Rectangle: public Shape { … } ;
class Ellipse: public Shape { … } ;

 

1. 순수 가상함수

순수 가상함수는 파생클래스에게 선언만을 물려준다.

(파생클래스가 순수가상함수를 다시 선언해야한다. 추상클래스는 전형적으로 정의를 갖지 않는다.)

하지만, 순수가상함수도 구현을 가질 있다.

, 구현이 붙은 순수가상함수를 호출하기 위해서는 반드시 "클래스 이름" 한정자로 붙여주어야 한다.

 

Shape *ps1 = new Rectangle;
ps1->draw();  // Rectangle::draw를 호출
ps1->Shape::draw(); // Shape:;draw를 호출

순수가상함수 정의 예제를 살펴보자.

class Airplane {
public :
  virtual void fly(const Airport& destination) = 0;
};

void Airplane :: fly(const Airpot& destination)  //순수가상함수의 구현
{
  주어진 목적지로 비행기를 날려보내는 기본 코드
}

class ModelA: public Airplane { //파생클래스 ModelA
public :
  virtual void fly(const Airport& destination)
  { Airplane::fly(destination); } //public 상속받았기에 순수가상함수도 상속받게된다. 순수가상함수의 선언부와 구현부를 상속받게 된다. 말한것처럼 순수가상함수를 호출하기 위해서는 클래스이름을 한정자로 붙여줘야한다.
};

class ModelB : public Airplane {
public:
 virtual void fly(const Airport& destination);
};
void ModelB::fly(const Airport& destination)
{
 주어진 목적지로 모델 B 비행기를 날려보내는 신규 코드
}

 

2. 단순(비순수) 가상함수

비순수 가상함수는 인터페이스 뿐만 아니라, 함수의 기본 구현도 받게한다.

" 샘플의 error 함수는 클래스설계자가 제공하는 기본 버전을 쓰셔도 되지만, 바꾸어서 사용가능하다"

 

3. 비가상함수

클래스 파생에 상관없이 변하지 않는 동작을 지정할때 쓰임

파생클래스가 함수의 선언(인터페이스) 구현을 물려받게한다.

샘플에서 objectID 특정객체의 식별자의 의도로 선언하였기에, 어떤 파생클래스에서도 동일한 방법으로 쓰일 것이다. 그래서 비가상함수를 사용하였다.

 

4. 클래스 설계시 실수 2가지 유형

  1) 모든 멤버함수를 비가상 함수로 선언

    보통 가상함수를 쓰면 가상테이블 크기로 인해 성능이 안좋을 알고 이와 같은 실수를 저지르는 경우가 있다. 비가상소멸자가 문제가 있기에 이를 염두하고 작성해야 한다.

  2) 모든 멤버함수를 가상함수로 선언

    분명 클래스만의 불변동작이 필요하다.

 

이것만은 잊지말자

1. 인터페이스 상속은 구현상속과 다르다. public상속에서 파생클래스는 기본클래스의 모든 인터페이스를 물려받는다.

2. 순수 가상함수는 인터페이스(선언) 상속을 허용한다.

3. 단순 가상함수는 인터페이스, 구현의 상속을 허용한다. 재정의도 가능

4. 비가상함수는 인터페이스 상속과 구현을 허용한다.(재정의는 불가)

댓글