Post

[ STUDY/Effective C++ ] 2022. 8. 17. 23:06

 

class Transaction {
public:
	Transaction();
	virtual void logTransaction() const = 0;
	...
};

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

class BuyTransaction: public Transaction { //Transaction의 파생 클래스
public:
	virtual void logTransaction() const;
	...
};
BuyTransaction b;

위와 같은 코드가 있을때 BuyTransaction b; 코드를 작성한다면 호출되는 logTransaction함수는 BuyTransaction의 것이 아니라 Transaction의 것이다.

 

기본클래스의 생성자가 호출 될 동안에는, 가상 함수는 절대로 파생 클래스 쪽으로 내려가지않는다.

( = 기본 클래스 생성과정에서는 가상함수가 먹히지않는다.)

 

왜냐하면 기본 클래스 생성자는 파생 클래스 생성자보다 앞서 실행되기때문에, 기본 클래스 생성자가 돌아가고 있을 시점에는 파생 클래스 데이터 멤버는 아직 초기화된 상태가 아니다.

 

파생클래스(BuyTransaction)만의 데이터가 아직 초기화된 상태가 아니기때문에 아예 없는것으로 취급하는게 안전하다고 생각하기때문에 파생클래스의 객체는 기본 클래스 부분이 생성되는 동안은, 기본 클래스타입의 객체로 취급한다.

 

그리고 C++은 초기화되지 않은 영역을 건드리는 것 자체를 못하도록 막기때문에 가상함수가 파생클래스 쪽으로 내려가지않는다.

 

소멸자 또한 마찬가지로 소멸자가 호출되고나면, C++은 파생 클래스만의 데이터 멤버를 없는것처럼 취급하고 진행한다.

 

 

 

 

이러한 문제점을 해결하기위해서는 어떻게해야할까?

class Transaction {
public:
	explict 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);
};

바로 가상함수를 비가상 멤버함수로 바꾸는것이다. 

위의 코드들을 예시로 들자면,

파생클래스의 생성자들이 필요한 로그 정보를 Transaction의 생성자로 넘기면=>

비가상 함수로 바꾼 logTransaction이 안전하게 수행된다. (정적 멤버로도 되어있기때문에 더욱더 안전)

 

필요한 초기화 정보를 파생클래스에서 기본 클래스 생성자로 올려준다는 얘기니

기존에 기본 클래스에서 정의한 가상함수를 파생클래스에서 사용할려고한 의도와 똑같이 사용이 가능하다.

▲ top