학습일지/C와 C++

C++ 인벤토리 시스템 구현

Tsukino Ren 2026. 3. 17. 20:34

인벤토리 시스템

우선 과제 항목 중 필수 기능만 우선 구현하였습니다.


Inventory.h

// Inventory.h

#pragma once
#include <iostream>

template <typename T>

class Inventory
{
public:
	Inventory(int capacity = 10)
	{
		if (capacity <= 0)
		{
			capacity_ = 1;
		}
		else
		{
			capacity_ = capacity;
		}

		size_ = 0;
		pItems_ = new T[capacity_];
	}
	
	~Inventory()
	{
		delete[] pItems_;
		pItems_ = nullptr;
	}

	void AddItem(const T& item)
	{
		if (size_ >= capacity_)
		{
			std::cout << "인벤토리가 꽉 찼습니다!" << std::endl;
			return;
		}
		
		pItems_[size_] = item;
		++size_;
	}

	void RemoveLastItem()
	{
		if (size_ <= 0)
		{
			std::cout << "인벤토리가 비어있습니다!" << std::endl;
			return;
		}
		
		pItems_[size_ - 1].Clear();
		--size_;
	}

	int GetSize() const
	{
		return size_;
	}

	int GetCapacity() const
	{
		return capacity_;
	}

	void PrintAllItems() const
	{
		if (size_ == 0)
		{
			std::cout << "비어있음" << std::endl;
			return;
		}

		for (int i = 0; i < size_; ++i)
		{
			pItems_[i].PrintInfo();
		}
	}

private:
	T* pItems_;
	int capacity_;
	int size_;
};

Item.h

// Item.h

#pragma once
#include <iostream>
#include <string>

class Item
{
public:
	Item()
		: name_(""), price_(0)
	{
	}

	Item(const std::string& name, int price)
		: name_(name), price_(price)
	{
	}

	const std::string& GetName() const
	{
		return name_;
	}

	int GetPrice() const
	{
		return price_;
	}

	void Clear()
	{
		name_ = "";
		price_ = 0;
	}

	void PrintInfo() const
	{
		std::cout << "[이름: " << name_ << ", 가격: " << price_ << "G]" << std::endl;
	}

private:
	std::string name_;
	int price_;
};

Main.cpp

// Main.cpp

#include "Inventory.h"
#include "Item.h"

int main(void)
{
	Inventory<Item>* itemInventory = new Inventory<Item>();

	for (int i = 0; i < 11; ++i)
	{
		itemInventory->AddItem(Item("Item" + std::to_string(i), i * 100));
	}

	std::cout << "\n";
	itemInventory->PrintAllItems();
	std::cout << "\n";

	for (int i = 0; i < 11; ++i)
	{
		itemInventory->RemoveLastItem();
	}

	std::cout << "\n";
	itemInventory->PrintAllItems();
	std::cout << "\n";

	delete itemInventory;
	return 0;
}

출력


왜 헤더에 구현했는가?

템플릿 template <typename T> 에서 T는 아직 정해지지 않은 상태입니다.

템플릿은 컴파일 시점에 생성되고 타입이 나중에 결정되기에 컴파일러가 구현을 항상 볼 수 있어야 합니다.

그래서 헤더에 구현까지 포함하여 사용하였습니다.


템플릿을 사용하지 않았을 때

class InventoryInt {
    int items[10];
};

class InventoryDouble {
    double items[10];
};

class InventoryString {
    std::string items[10];
};

문제점

  • 코드 중복 발생으로 로직은 똑같은데 타입만 다르거나 클래스를 계속 추가해야됨
  • 수정할 때 전부 고쳐야 하는 문제점이 발생함

템플릿을 사용했을 때

template <typename T>
class Inventory 
{
    T items[10];
};
  • 코드 재사용이 간편함
  • 수정이 필요한 부분만 고치면되서 유지보수가 쉬움
  • 컴파일 단계에서 타입 문제를 실행 전에 검수해줌
  • 컴파일 시 코드 생성 하므로 성능이 좋음
  • 새로운 타입 추가하기 간편함

마무리

내일 과제 제출 마감일이니 도전과제도 해보면서 전체적으로 다시한번 작성해보면서 해당 기능들이 왜 쓰이는지 제대로 파악해볼 예정입니다.


2026.03.18 도전기능 과제 추가

Inventory.h

// Inventory.h

#pragma once
#include <algorithm>
#include <iostream>
#include "Item.h"

template <typename T> 

class Inventory
{
public:
	~Inventory()
	{
		delete[] pItems_;
		pItems_ = nullptr;
	}

	Inventory(int capacity = 10)
	{
		if (capacity <= 0)
		{
			capacity_ = 1;
		}
		else
		{
			capacity_ = capacity;
		}

		size_ = 0;
		pItems_ = new T[capacity_];
	}

	void AddItem(const T& item)
	{
		if (size_ >= capacity_)
		{
			Resize(capacity_ * 2);
		}

		pItems_[size_] = item;
		++size_;
	}

	void RemoveLastItem()
	{
		if (size_ <= 0)
		{
			std::cout << "인벤토리가 비어있습니다!" << std::endl;
			return;
		}

		--size_;
	}

	int GetSize() const
	{
		return size_;
	}

	int GetCapacity() const
	{
		return capacity_;
	}

	void PrintAllItems() const
	{
		if (size_ == 0)
		{
			std::cout << "비어 있다!" << std::endl;
			return;
		}

		for (int i = 0; i < size_; ++i)
		{
			pItems_[i].PrintInfo();
		}
	}

	void Resize(int newCapacity)
	{
		if (newCapacity <= capacity_)
		{
			return;
		}

		T* pNewItems = new T[newCapacity];

		for (int i = 0; i < size_; ++i)
		{
			pNewItems[i] = pItems_[i];
		}

		delete[] pItems_;
		pItems_ = pNewItems;
		capacity_ = newCapacity;
	}

	void SortItems()
	{
		std::sort(pItems_, pItems_ + size_, compareItemsByPrice);
	}

	Inventory(const Inventory<T>& other)
	{
		capacity_ = other.capacity_;
		size_ = other.size_;
		pItems_ = new T[capacity_];

		for (int i = 0; i < size_; ++i)
		{
			pItems_[i] = other.pItems_[i];
		}
	}

	void Assign(const Inventory<T>& other)
	{
		if (this == &other)
		{
			return;
		}

		delete[] pItems_;

		capacity_ = other.capacity_;
		size_ = other.size_;
		pItems_ = new T[capacity_];

		for (int i = 0; i < size_; ++i)
		{
			pItems_[i] = other.pItems_[i];
		}
	}

private:
	T* pItems_;
	int capacity_;
	int size_;
};

Item.h

// Item.h

#pragma once
#include <iostream>
#include <string>

class Item
{
public:
	Item();
	Item(const std::string& name, int price);

	const std::string& GetName() const;
	int GetPrice() const;
	void PrintInfo() const;

private:
	std::string name_;
	int price_;
};

inline bool compareItemsByPrice(const Item& a, const Item& b)
{
	return a.GetPrice() < b.GetPrice();
}

Item.cpp

// Item.cpp

#include "Item.h"

Item::Item() : name_(""), price_(0)
{
}

Item::Item(const std::string& name, int price)
	: name_(name), price_(price)
{
}

const std::string& Item::GetName() const
{
	return name_;
}

int Item::GetPrice() const
{
	return price_;
}

void Item::PrintInfo() const
{
	std::cout << "[이름: " << name_ << ", 가격: " << price_ << "G]" << std::endl;
}

Main.cpp

// Main.cpp

#include "Inventory.h"
#include "Item.h"

struct ItemData
{
	std::string name;
	int price;
};

ItemData itemList[] =
{
	{"철검", 1000},
	{"철방패", 800},
	{"생명력 포션", 50},
	{"마나 포션", 80},
	{"스태미나 포션", 50},
	{"공격력 증가 포션", 200},
	{"고블린의 귀", 10},
	{"고블린의 눈", 15},
	{"고블린의 가죽", 15},
	{"오크의 가죽", 100},
	{"고블린의 조잡한 돌검", 1},
	{"오크의 대검", 2000},
	{"거미줄", 2},
	{"양털", 2},
	{"우유", 3},
	{"빵", 5},
	{"숙소 열쇠", 0},
	{"손질이 필요한 갑옷", 3000},
	{"손질이 필요한 건틀렛", 2000},
	{"손질이 필요한 그리브", 2000}
};

int main(void)
{
	Inventory<Item>* itemInventory = new Inventory<Item>();

	for (int i = 0; i < 11; ++i)
	{
		itemInventory->AddItem(Item(itemList[i].name, itemList[i].price));
	}
	
	std::cout << "\n==== 필수 과제 인벤토리 ====\n";
	itemInventory->PrintAllItems();
	std::cout << "\nItemCapacity : " << itemInventory->GetCapacity() << std::endl;

	itemInventory->Resize(25);
	for (int i = 0; i < 20; ++i)
	{
		itemInventory->AddItem(Item(itemList[i].name, itemList[i].price));
	}
	
	std::cout << "\n==== 도전 과제 인벤토리 ====\n";
	itemInventory->PrintAllItems();
	std::cout << "\nItemCapacity : " << itemInventory->GetCapacity() << std::endl;

	std::cout << "\n==== 정렬 후 인벤토리 ====\n";
	itemInventory->SortItems();
	itemInventory->PrintAllItems();

	std::cout << "\n==== 복사된 인벤토리 ====\n";
	Inventory<Item>* itemInventory2 = new Inventory<Item>(*itemInventory);
	itemInventory2->PrintAllItems();

	delete itemInventory;
	itemInventory = nullptr;

	delete itemInventory2;
	itemInventory2 = nullptr;

	return 0;
}

추가 및 변경점

  • Item 클래스 같은 경우 헤더에 다 구현하던걸 헤더와 cpp로 나눠서 다시 구현하엿음
  • 인벤토리가 가득 찻을 때 Resize를 통해 메모리 재할당 받아 2배 만큼 가방 공간이 늘어나게 함
  • std::sort를 통해 정렬하는 법을 배움
  • 깊은 복사...부분은 더 공부가 필요하다

'학습일지 > C와 C++' 카테고리의 다른 글

C++ 콘솔 RPG 만들기  (0) 2026.03.19
C++ 스마트 포인터  (0) 2026.03.18
C++ Debugging  (0) 2026.03.16
Moderen C++  (1) 2026.03.15
C++ Vector  (0) 2026.03.14