[TIL] 24-01-11

Lev·2024년 1월 11일
0

📓TIL Archive

목록 보기
22/33

클래스

Inner Class

#include <iostream>
#include <vector>

class Image
{

};

class Inventory
{
private:
	// 속해 있는 개념일 경우 바깥에 따로 두어도 상관은 없지만,
	// 이너클래스를 private 안에 둠으로써 바깥에서 접근할 수 없는 클래스로 만들 수 있다.
	class InventoryIcon	// [Inner Class]
	{
	public:
		void Test()
		{
			Icons;	// 불가능
			//InventoryIcon은 개념적으로 Inventory에 속해 있다고 생각되어
			//이너클래스로 작성되었을 뿐, 실제론 Inventory 바깥에 있는 별개의 클래스와 같다.
		}

	private:
		Image Icon;
		int Count;
	};

	std::vector<InventoryIcon> Icons;
};

int main()
{
	Inventory Inventory;

	// Inventory::InventoryIcon Icon;
	// 중첩된 클래스는 (public일 경우) ::으로 접근할 수 있다.
}

friend

/*
[friend]
기본적으로 서로 다른 클래스 간에 private에는 접근할 수 없다.
하지만 friend 선언을 해주면 예외를 만들 수 있다.
(사실 객체지향적으로는 불가능하지만, C++에서는 가능하다)

(+)
- 특정 경우메만 접근을 허용하고 싶을 때, 해당 멤버를 public으로 만들지 않아도 된다

(-)
- 남발할수록 좋지 못한 문법이다
- 다른 클래스의 private에 접근해야 할 경우에, 다른 구조적 방법으로 해결할 생각부터 해보자
*/

class A
{
	friend class B;							// B 클래스 전체가 firend
	// friend void B::BFunction(A& _Other);	// B 클래스의 BFunction만 friend

private:
	int Value;
};

class B
{
public:
	void Test(A& _Other)
	{
		_Other.Value;	// 접근 가능
	}

private:
	void BFunction(A& _Other)
	{
		_Other.Value;	// 접근 가능
	}
};

class C
{
public:
	void Test(A& _Other)
	{
		_Other.Value;	// 접근 불가능
	}
};

자료구조

list

/*
[List]
노드를 사용하는 시퀀스 컨테이너
  - std::list는 양방향 노드를 사용하는 양방향 리스트이다.
  - 벡터와 달리 랜덤엑세스가 불가하다
	VectorValue[0]	(가능)
	ListValue[0]	(불가능)
*/
#include <iostream>
#include <Windows.h>
#include <assert.h>
#include <list>

typedef int DataType;

// MyList 구현
class MyList
{
private:
	class ListNode	// 이너클래스
	{
	public:	// 어짜피 ListNode는 MyList 안에서만 사용되므로 public이어도 된다
		DataType Data = DataType();	// 노드는 데이터를 1개 받는다
		ListNode* Next = nullptr;
		ListNode* Prev = nullptr;
	};

public:
	/*
	[iterator]
	자료구조의 순회를 담당하는 클래스
	- std의 거의 모든 자료구조는 이터레이터라는 통일된 인터페이스를 사용한다.
	- 사실 vector도 이터레이터를 활용하여 내부 전체를 순회할 수 있다.
	*/
	class iterator
	{
	public:
		friend MyList;
		// MyList의 erase()에서 iterator의 private 멤버변수인 CurNode에 접근하기 위해 firend 선언

		/*
		friend MyList;			=> friend 선언
		friend class MyList;	=> MyList 클래스 전방선언과 동시에 friend 선언
		여기선 이미 MyList를 알고 있기 때문에 전방선언할 필요가 없다.
		*/

		iterator()
		{

		}

		iterator(ListNode* _CurNode)
			: CurNode(_CurNode)
		{

		}

		bool operator!=(const iterator& _Other)
		{
			return CurNode != _Other.CurNode;
		}

		void operator++()
		{
			CurNode = CurNode->Next;
		}

		DataType& operator*()
		{
			return CurNode->Data;
		}

	private:
		ListNode* CurNode = nullptr;
	};

public:
	MyList()
	{
		Start->Next = End;
		End->Prev = Start;
	}

	~MyList()
	{
		// Start, End 포함 모든 노드의 메모리 반환
		ListNode* CurNode = Start;
		while (CurNode)
		{
			ListNode* Next = CurNode->Next;
			if (CurNode != nullptr)
			{
				delete CurNode;
				CurNode = Next;
			}
		}
	}

	iterator begin()
	{
		return iterator(Start->Next);
	}

	iterator end()
	{
		return iterator(End);
	}

	// End의 Prev에 새로운 데이터 추가
	void push_back(const DataType& _Data)
	{
		ListNode* NewNode = new ListNode();

		NewNode->Data = _Data;
		NewNode->Next = End;
		NewNode->Prev = End->Prev;

		ListNode* PrevNode = NewNode->Prev;
		ListNode* NextNode = NewNode->Next;

		PrevNode->Next = NewNode;
		NextNode->Prev = NewNode;
	}

	// Start의 Next에 새로운 데이터 추가
	void push_front(const DataType& _Data)
	{
		ListNode* NewNode = new ListNode();

		NewNode->Data = _Data;
		NewNode->Next = Start->Next;
		NewNode->Prev = Start;

		ListNode* PrevNode = NewNode->Prev;
		ListNode* NextNode = NewNode->Next;

		PrevNode->Next = NewNode;
		NextNode->Prev = NewNode;
	}

	// 현재 노드를 지우고, 다음 노드를 return
	iterator erase(iterator& _Iter)
	{
		if (_Iter.CurNode == Start)
		{
			MessageBoxA(nullptr, "Start를 삭제하려고 했습니다.", "치명적 에러", MB_OK);
			assert(false);
		}

		if (_Iter.CurNode == End)
		{
			MessageBoxA(nullptr, "End를 삭제하려고 했습니다.", "치명적 에러", MB_OK);
			assert(false);
		}

		iterator ReturnIter;

		if (_Iter.CurNode != nullptr)
		{
			ReturnIter = iterator(_Iter.CurNode->Next);

			ListNode* PrevNode = _Iter.CurNode->Prev;
			ListNode* NextNode = _Iter.CurNode->Next;

			PrevNode->Next = NextNode;
			NextNode->Prev = PrevNode;

			delete _Iter.CurNode;
			_Iter.CurNode = nullptr;
		}

		return ReturnIter;
	}

private:
	// 시작과 끝을 표현하는 더미노드
	ListNode* Start = new ListNode();
	ListNode* End = new ListNode();
};

int main()
{
	_CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF | _CRTDBG_ALLOC_MEM_DF);

	{
		std::cout << "std::list" << std::endl;
		std::list<int> NewList = std::list<int>();

		for (int i = 0; i < 10; i++)
		{
			NewList.push_back(i);
			// NewList.push_front(i);
		}

		std::list<int>::iterator StartIter = NewList.begin();
		std::list<int>::iterator EndIter = NewList.end();

		StartIter = NewList.erase(StartIter);

		for (/*std::list<int>::iterator StartIter = NewList.begin();*/
			; StartIter != EndIter; ++StartIter)
		{
			std::cout << *StartIter << std::endl;
		}
	}
	{
		std::cout << "MyList" << std::endl;
		MyList NewList = MyList();

		for (int i = 0; i < 10; i++)
		{
			NewList.push_back(i);
			// NewList.push_front(i);
		}

		MyList::iterator StartIter = NewList.begin();
		MyList::iterator EndIter = NewList.end();

		StartIter = NewList.erase(StartIter);

		for (; StartIter != EndIter; ++StartIter)
		{
			std::cout << *StartIter << std::endl;
		}

		/*
		만약 소멸자에서 동적할당된 메모리를 반환하지 않았다면,
		Start, 1, 2, 3, 4, 5, 6, 7, 8, 9, End
		이렇게 총 11개의 노드에서 각각 24bytes씩 memory leak이 발생한다.
		*/
	}
}

과제

240111_RList

// <과제> reverse_iterator를 만들자
#include <iostream>
#include <list>
#include <ConsoleEngine/EngineDebug.h>

typedef int DataType;

class MyList
{
private:
	class ListNode
	{
	public:
		DataType Data = DataType();
		ListNode* Next = nullptr;
		ListNode* Prev = nullptr;
	};

	// iterator와 reverse_iterator는 공통된 코드가 많기 때문에
	// 공통된 부분을 묶어 iterator_Base라는 부모 클래스를 만들어준다
	class iterator_Base
	{
	public:
		iterator_Base()
		{

		}

		iterator_Base(ListNode* _CurNode)
			: CurNode(_CurNode)
		{

		}

		DataType& operator*()
		{
			return CurNode->Data;
		}

		bool operator!=(const iterator_Base& _Other)
		{
			return CurNode != _Other.CurNode;
		}
		
		ListNode* CurNode = nullptr;
	};

public:
	class iterator : public iterator_Base
	{
		friend MyList;

	public:
		iterator()
		{

		}

		iterator(ListNode* _CurNode)
			: iterator_Base(_CurNode)
		{

		}

		void operator++()
		{
			CurNode = CurNode->Next;
		}
	};

	// 과제
	class reverse_iterator : public iterator_Base	// 상속
	{
		friend MyList;

	public:
		reverse_iterator()
		{

		}

		reverse_iterator(ListNode* _CurNode)
			: iterator_Base(_CurNode)
		{

		}

		void operator++()
		{
			CurNode = CurNode->Prev;
		}
	};

	MyList()
	{
		Start->Next = End;
		End->Prev = Start;
	}

	~MyList()
	{
		ListNode* CurNode = Start;
		while (CurNode)
		{
			ListNode* Next = CurNode->Next;
			if (nullptr != CurNode)
			{
				delete CurNode;
				CurNode = Next;
			}
		}
	}

	iterator begin()
	{
		return iterator(Start->Next);
	}

	iterator end()
	{
		return iterator(End);
	}

	// 과제
	reverse_iterator rbegin()
	{
		return reverse_iterator(End->Prev);
	}

	// 과제
	reverse_iterator rend()
	{
		return reverse_iterator(Start);
	}

	void push_back(const DataType& _Data)
	{
		ListNode* NewNode = new ListNode();
		NewNode->Data = _Data;

		NewNode->Next = End;
		NewNode->Prev = End->Prev;

		ListNode* PrevNode = NewNode->Prev;
		ListNode* NextNode = NewNode->Next;

		PrevNode->Next = NewNode;
		NextNode->Prev = NewNode;
	}

protected:

private:
	ListNode* Start = new ListNode();
	ListNode* End = new ListNode();
};

int main()
{
	LeakCheck;

	{
		std::cout << "std::list" << std::endl;
		std::list<int> NewList = std::list<int>();

		for (int i = 0; i < 5; i++)
		{
			NewList.push_back(i);	// 0, 1, 2, 3, 4
		}

		std::list<int>::reverse_iterator rStartIter = NewList.rbegin();
		std::list<int>::reverse_iterator rEndIter = NewList.rend();

		for (; rStartIter != rEndIter; ++rStartIter)
		{
			std::cout << *rStartIter << std::endl;	// 4, 3, 2, 1, 0
		}
	}

	{
		std::cout << "MyList" << std::endl;
		MyList NewList = MyList();

		for (int i = 0; i < 5; i++)
		{
			NewList.push_back(i);	// 0, 1, 2, 3, 4
		}

		MyList::reverse_iterator rStartIter = NewList.rbegin();
		MyList::reverse_iterator rEndIter = NewList.rend();

		for (; rStartIter != rEndIter; ++rStartIter)
		{
			std::cout << *rStartIter << std::endl;	// 4, 3, 2, 1, 0
		}
	}
}
profile
⋆꙳⊹⋰ 𓇼⋆ 𝑻𝑰𝑳 𝑨𝑹𝑪𝑯𝑰𝑽𝑬 ⸝·⸝⋆꙳⊹⋰

0개의 댓글