본문 바로가기
Book & Lecture/Effective C++

Effective C++ 항목9 : 객체 생성 및 소멸 과정 중에는 절대로 가상 함수를 호출하지 말자

by studio ODOC 2023. 2. 12.
반응형

Effective C++ 항목9

객체 생성 및 소멸 과정 중에는 절대로 가상 함수를 호출하지 말자

 

 

  • 객체 생성 및 소멸 과정 중에는 절.대.로 가상 함수를 호출해선 안된다!!
// 기본 클래스
class Transaction
{
  public:
    Transaction();
    virtual void logTransaction() const = 0;     // 타입에 따라 달라지는 로그 기록
    ...
};

// 기본 클래스 생성자
Transaction::Transaction()
{ 
  logTransaction(); 
}

// Transaction 의 파생 클래스
class BuyTransaction : public Transaction
{
  public:
    // Transaction 타입에 따른 거래내역 로깅
    virtual void logTransaction() const;
    ...
}

...

// 아래의 코드가 실행될 때 어떻게 되는지??
BuyTransaction b;
  • 위 코드에서 마지막으로 생성되는 BuyTransaction 객체에 의해 BuyTransaction 생성자 호출
    • 왜냐면, 파생 클래스 객체가 생성될 때 그 객체의 기본 클래스 부분이 파생 클래스 부분보다 먼저 호출되므로!
    • 기본 클래스 생성 과정에서는 가상 함수가 먹히지 않음
    • 파생 클래스 객체의 기본 클래스 부분이 생성되는 동안에는 생성 중인 객체의 타입이 잠시 기본 클래스로 설정됨
      • 이로 인해 BuyTransaction 생성하는 과정에서 미정의 동작이 발생 가능함
      • 파생 클래스의 생성자 실행이 시작되어야만 그 객체가 비로소 파생 클래스 객체의 면모를 가짐
    • 이 문제의 해결 방법은?
      • => logTransaction을 Transaction 클래스의 비가상 멤버 함수로 바꾸는 것!!
      • 아래 코드 참고
class Transaction
{
  public:
    explicit Transaction(const std::string& logInfo);
    // 이제는 비가상 함수로 생성
    void logTransaction(const std::string& logInfo) const;
};

Transaction::Transaction(const std::string& logInfo)
{ 
  // 비가상 함수 호출하므로 문제 해결
  logTransaction(logInfo); 
}

class BuyTransaction : public Transaction
{
  public:
    BuyTransaction( parameters )
      : Transaction(createLogString( parameters )) // 로그 정보를 기본 클래스 생성자로 넘김
    { ... }
    
  private:
    static std::string createLogString( parameters );
};
  • '미초기화된 데이터 멤버는 정의되지 않은 상태에 있다'
    • 때문에 기본 클래스 부분의 생성과 소멸이 진행되는 동안에 호출되는 가상함수는 파생 클래스 쪽으로 내려갈 수 없음!!

 

요약

1. 생성자, 소멸자 안에서는 가상 함수를 호출하지 말자

2. virtual로 선언했을지라도 기본 클래스 생성자를 실행하는 동안에는 파생 클래스 쪽으로 내려갈 수 없기 때문!

반응형