C++

2. Base From Member Idiom

튀김족발 2022. 12. 4. 16:10

우선 Idiom이 무엇인지 부터 알아보자

 

C++ Idiom

프로그래밍시 발생하는 문제를 해결하기 위한 기법.
C++의 언어적인 특성에 기반한 팁 문제해결 패턴이다.

(https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms)

 

이 수많은 Idiom 중에 Base From Member Idiom 을 알아보자 (나머지는 추후 업로드 하거나 안하거나 미래의 나만 알 것 같다...)

 

Base From Member Idiom

#include <iostream>

class KObject
{
public:
	KObject()
	{
		m_iInitialized = 99;
	}

	int GetInitialized() const
	{
		return m_iInitialized;
	}
	 
private:
	int m_iInitialized;
};

class KBase
{
public:
	KBase(KObject& obj)
	{
		std::cout << obj.GetInitialized() << std::endl;
	}
};

class KDerived1 : public KBase
{
public:
	KDerived1() : KBase(m_object)
	{

	}

private:
	KObject m_object;
};

int main()
{
	KDerived1 d1;
}

위에 Idiom을 알아보기 위한 코드이다.

 

d1을 생성하게 되면 어떤 값이 출력이 될까? 99가 출력이 될까?

예상과는 다르게 쓰레기 값이 출력이 된다.

음... 무슨 문제일까

 

문제는

class KDerived1 : public KBase
{
public:
	KDerived1() : KBase(m_object)
	{

	}

private:
	KObject m_object;
};

이 KDerived1 생성자 이다.

 

KDerived1의 m_object의 메모리를 할당 받고 생성자를 호출하기 전에 KBase의 생성자가 호출이 된다.

따라서 

KBase(KObject& obj)
{
	std::cout << obj.GetInitialized() << std::endl;
}

이 부분에서 obj는 생성자가 호출이 안된 객체로 메모리만 할당돼 있는 상태이기 때문에 99가 출력이 안되고 쓰레기값이 출력이 된다.

 

어떤 방법으로 이 문제를 해결할 수 있을까?

해결

struct PrivateBase
{
	KObject m_object;
};

class KDerived2 : protected PrivateBase, public KBase
{
public:	
	KDerived2() : KBase(m_object)
	{

	}
};

이런식으로 두가지를 상속받는 방법으로 해결이 가능하다. C++에서 두개 이상 상속을 받는것은 위험한 방법이지만, 기능 추가를 위해 받는 방법은 종종 사용한다고 한다.

 

protected PrivateBase, public KBase 이렇게 돼있다면 순서대로 PrivateBase, KBase 순으로 상속이 진행 된다.

따라서 PrivateBase의 m_object가 먼저 생성이 되고, KBase가 생성이 되면서 위에 문제를 해결할 수 있게 된다.

 

#include <iostream>

class KObject
{
public:
	KObject()
	{
		m_iInitialized = 99;
	}

	int GetInitialized() const
	{
		return m_iInitialized;
	}
	 
private:
	int m_iInitialized;
};

class KBase
{
public:
	KBase(KObject& obj)
	{
		std::cout << obj.GetInitialized() << std::endl;
	}
};

class KDerived1 : public KBase
{
public:
	KDerived1() : KBase(m_object)
	{

	}

private:
	KObject m_object;
};

struct PrivateBase
{
	KObject m_object;
};

class KDerived2 : protected PrivateBase, public KBase
{
public:	
	KDerived2() : KBase(m_object)
	{

	}
};

int main()
{
	KDerived1 d1;
	KDerived2 d2;
}

KDerived1 과는 다르게 KDerived2에서는 99를 출력 하게 된다.