반응형
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로 선언했을지라도 기본 클래스 생성자를 실행하는 동안에는 파생 클래스 쪽으로 내려갈 수 없기 때문!
반응형
'Book & Lecture > Effective C++' 카테고리의 다른 글
Effective C++ 항목11 : operator에서는 자기대입에 대한 처리가 빠지지 않도록 하자 (0) | 2023.02.18 |
---|---|
Effective C++ 항목10: 대입 연산자는 *this의 참조자를 반환하게 하자 (0) | 2023.02.13 |
Effective C++ 항목8 : 예외가 소멸자를 떠나지 못하도록 붙들어 놓자 (0) | 2023.02.06 |
Effective C++ 항목7 : 다형성을 가진 기본 클래스에서는 소멸자를 반드시 가상 소멸자로 선언하자. (0) | 2023.02.05 |
Effective C++ 항목6 : 컴파일러가 만들어낸 함수가 필요 없다면 사용을 금지하자 (0) | 2023.01.27 |