2021 시작

밑의 코드를 봐보자

class Transaction					//모든 거래에 대한
{							//기본 클래스
public:										
	Transaction();								
	virtual void logTransaction() const = 0;	//타입에 따라 달라지는
							//로그 기록을 만든다.
	....;
};

Transaction::Transaction()					//기본 클래스 생성자의 구현
{
	...;
	logTransaction();				//마지막 동작으로, 이 거래를
}							//로깅을 구현한다.

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

class SellTransaction : public Transaction		//역시 파생 클래스
{
public:
	virtual void logTransaction() const;		//이 타입에 따른 거래 내역
};							//로깅을 구현한다.

BuyTransaction b;

 

이 코드를 보면 기본 클래스 생성자에서 가상 함수를 호출하고 있다. 이러면 큰일 난다. 왜? 한번 생각해보자 우리가 파생 클래스를 만들면 파생 클래스를 바로 초기화하는 것이 아니고 기본 클래스를 먼저 초기화한다는 것이다. C++의 배려로 우리가 초기화 안된 파생 클래스의 가상 함수 호출 대신 지금 생성자가 호출되는 클래스의 가상 함수를 사용한다.(더 자세한 동작 과정은 _vfptr의 동작을 잘 생각해봐야행 ㅇㅇ..) 소멸자도 마찬가지 ㅇㅇ

아 그리고 당연하지만 아래의 코드도 하면 안 된다.

class Transaction 
{
public:
	Transaction();
	{init(); }			//비 가상멤버 함수를 호출하고 있...

	virtual void logTransaction() const = 0;

	.....;
private:
	void init() 
	{
		logTransaction();	//...는데 이 비가상 함수에서
							//가상 함수를 호출하고 있어!
	}
};

 

하지만 이렇게 생성자에 가상함수를 넣은 것 같은 효과를 볼 수 있는 방법이 있다. logTransaction을 비 가상 함수로 만들어 필요한 초기화 정보를 파생 클래스에서 기본 클래스로 올려주는 것이다.

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		//Transaction 파생 클래스
{
private:
	static std::string CreateLogString(parameters);
public:

	BuyTransaction(parameters)		//로그 정보를
		: Transaction(CreateLogString(parameters)) {}	//기본 클래스
	....;							//생성자로 넘긴다.
};

BuyTransaction b;

 

이것만은 잊지 말자!

1. 생성자 혹은 소멸자 안에서 가상 함수를 호출하지 말자. 가상 함수라고 해도, 지금 실행 중인 생성자나 소멸자에 해당되는 클래스의 파생 클래스 쪽으로는 내려가지 않으니까

공유하기

facebook twitter kakaoTalk kakaostory naver band
loading