언어/C++

[Effective C++] 다형성을 가진 기본 클래스에서는 소멸자를 반드시 가상 소멸자로 선언하자

2020. 1. 7. 21:23
반응형

항목 7 : 다형성을 가진 기본 클래스에서는 소멸자를 반드시 가상 소멸자로 선언하자

 

시간 기록에 관련된 TimeKeeper이라는 클래스를 선언하겠습니다.

 

1
2
3
4
5
6
7
8
9
10
class TimeKeeper{
public :
    TimeKeeper();
    ~TimeKeeper();
    ...
};
 
class AtomicClock : public TimeKeeper { ... };
class WaterClock : public TimeKeeper { ... };
class WristWatch : public TimeKeeper { ... };
 

이 클래스의 혜택을 받는 사용자들은 시간 정보에 접근하고 싶어 합니다. 시간 계산이 어떻게 되는지에 대해서는 신경 쓰고 싶지 않고요. 사정이 이렇기 때문에, 어떤 시간기록 객체에 대한 포인터를  손에 넣는 용도로 팩토리 함수(새로 파생된 파생 클래스 객체에 대한 기본 클래스 포인터를 반환하는 함수)를 만들어 두면 좋을 것 같습니다.

 

1
TimeKeeper* getTimeKeeper();    // TimeKeeper에서 파생된 클래스를 통해 동적으로 할당된 객체의 포인터를 반환합니다.
 

팩토리 함수의 기존 규약을 그대로 따라간다면 getTimeKeeper 함수에서 반환되는 객체는 힙에 있게 되므로, 결국 메모리 및 기타 자원의 누출을 막기 위해 해당 객체를 적절히 삭제해야 합니다.

 

1
2
3
TimeKeeper *ptk = getTimeKeeper();        // TimeKeeper클래스 계통으로부터 동적으로 할당된 객체를 얻습니다.
...                                        // 이 객체를 사용합니다.
delete ptk;                                // 자원 누출을 막기 위해 해제(삭제)합니다.
 
 

 

이 코드에서 발생할 수 있는 문제는 getTimeKeeper 함수가 반환하는 포인터가 파생 클래스 객체에 대한 포인터라는 점과 이 포인터가 가리키는 객체가 삭제될 떄는 기본 클래스 포인터를 통해 삭제된다는 점, 그리고 결정적으로 기본 클래스에 들어있는 소멸자가 비가상 소멸자라는 점입니다.

C++의 규정에 의하면, 기본 클래스 포인터를 통해 파생 클래스 객체가 삭제될 때 그 기본 클래스에 비가상 소멸자가 들어 있으면 프로그램 동작은 미정의 사항이라고 되어 있습니다.

대개 그 객체의 파생 클래스 부분이 소멸되지 않게 되지요.

 

이 문제를 해결하는 방법은 간단합니다.

기본 클래스에게 가상 소멸자를 주면 됩니다.

 

1
2
3
4
5
6
7
8
9
10
class TimeKeeper{
public :
    TimeKeeper();
    virtual ~TimeKeeper();
    ...
};
 
TimeKeeper *ptk = getTimeKeeper();
...
delete ptk;                                // 이제 제대로 동작합니다.
 

 

기본 클래스의 손에 가상 소멸자를 쥐어 주자는 규칙은 다형성을 가진 기본 클래스, 그러니까 기본 클래스 인터페이스를 통해 파생 클래스 타입의 조작을 허용하도록 설계된 기본 클래스에만 적용된다는 사실을 알아야 합니다.

 

꼭 잊지 말아야 할 것!

1. 다형성을 가진 기본 클래스에는 반드시 가상 소멸자를 선언해야 한다. 즉, 어떤 클래스가 가상 함수를 하나라도 갖고 있으면, 이 클래스의 소멸자도 가상 소멸자이어야 한다.

2. 기본 클래스로 설계되지 않았거나 다형성을 갖도록 설계되지 않은 클래스에는 가상 소멸자를 선언하지 말아야 한다.

 

반응형

'언어 > C++' 카테고리의 다른 글

[Effective C++] 객체 생성 및 소멸 과정 중에는 절대로 가상 함수를 호출하지 말자  (0) 2020.01.09
[Effective C++] 예외가 소멸자를 떠나지 못하도록 붙들어 놓자  (0) 2020.01.08
[Effective C++] 컴파일러가 만들어낸 함수가 필요 없으면 확실히 이들의 사용을 금해 버리자  (0) 2020.01.06
[Effective C++] C++가 은근슬쩍 만들어 호출해 버리는 함수들에 촉각을 세우자  (0) 2020.01.05
[Effective C++] 객체를 사용하기 전에 반드시 그 객체를 초기화하자  (0) 2020.01.04
'언어/C++' 카테고리의 다른 글
  • [Effective C++] 객체 생성 및 소멸 과정 중에는 절대로 가상 함수를 호출하지 말자
  • [Effective C++] 예외가 소멸자를 떠나지 못하도록 붙들어 놓자
  • [Effective C++] 컴파일러가 만들어낸 함수가 필요 없으면 확실히 이들의 사용을 금해 버리자
  • [Effective C++] C++가 은근슬쩍 만들어 호출해 버리는 함수들에 촉각을 세우자
지나가던 개발자
지나가던 개발자
지나가던 개발자
나의 발전을 위한 공간
지나가던 개발자
전체
오늘
어제
  • 분류 전체보기 (221)
    • 언어 (86)
      • C++ (43)
      • JAVA (43)
    • 게임 개발 (4)
      • 간단한 RPG 게임 만들기 (4)
      • 게임 개발 이슈 해결 (0)
    • 백준 문제풀이 (36)
      • PLATINUM (0)
      • GOLD (13)
      • SILVER (21)
      • BRONZE (2)
    • 프로그래머스 문제풀이 (32)
      • LEVEL 5 (0)
      • LEVEL 4 (0)
      • LEVEL 3 (7)
      • LEVEL 2 (19)
      • LEVEL 1 (6)
    • SQL 문제풀이 (15)
      • 프로그래머스 (4)
      • 해커랭크 (11)
    • 디자인 패턴 (1)
    • 웹 (17)
      • 웹 이론 정리 (17)
    • CS 지식 (28)
      • 알고리즘 (0)
      • 데이터베이스 (11)
      • 자료구조 (0)
      • 네트워크 (7)
      • 그래픽스 (0)
      • 운영체제 (9)
      • 기타 (1)
    • Git (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록
  • 깃 허브

공지사항

인기 글

태그

  • 상속
  • Chapter 4
  • 열거 타입과 애너테이션
  • 클래스와 인터페이스
  • 백준
  • 설계 및 선언
  • mysql
  • level 1
  • Chapter 6
  • java
  • Level 2
  • 객체 지향 설계
  • 객체 생성과 파괴
  • c++
  • Gold 5
  • Silver 3
  • 해커랭크
  • 프로그래머스
  • 소멸자 및 대입 연산자
  • BOJ

최근 댓글

최근 글

hELLO · Designed By 정상우.
지나가던 개발자
[Effective C++] 다형성을 가진 기본 클래스에서는 소멸자를 반드시 가상 소멸자로 선언하자
상단으로

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.