오늘의 목표
- 아침 코드카타
- 과제 2번 도전과제 완료
- 과제 3번
- 과제 4번
추가 목표:
과제 5번
1. 아침 코드카타
<문제> 콜라츠 추측
내가 작성한 코드:
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
int solution(int num) {
int answer = 0;
long long n = (long long)num;
while (n != 1 && answer <= 500) {
if (n % 2 == 0) {
n = n / 2;
}
else {
n = n * 3 + 1;
}
++answer;
}
if (n != 1) {
answer = -1;
}
return answer;
}
다른 사람들의 답변을 참고해 보니 더 간단하게 작성할 수 있는 방법이 있었다.
바로 삼항 연산자 사용하기.
간략한 코드 (삼항 연산자 사용)
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
int solution(int num) {
long long answer = num;
for(int i = 0; i < 500; ++i) {
if ( answer == 1 ) {
return answer;
}
answer = (answer % 2 == 0) ? (answer / 2) : (3 * answer + 1);
}
return -1;
}
[분석]
최대 연산 횟수가 정해져 있으니 for문을 사용하는 것이 더 적절한 것 같다.
만약에 조건을 충족하면 바로 인덱스값을 return해 종료시키면 되니까 더 효율적인듯.
만약 500번 연산을 완료 후 for문 밖으로 빠져나오게 된다면 -1을 반환시킨다.
2. [3번 과제] 인벤토리 시스템 구현
1. 데이터 보관함 Inventory<T> 클래스 설계
#pragma once
template <typename T>
class Inventory
{
public:
Inventory(int capacity = 10);
~Inventory();
private:
T* pItems_; // 아이템 객체 저장
int capacity_; // 인벤토리 최대 공간
int size_; // 저장된 아이템 개수
};
[주의]
동적할당 포인터변수 T* pItems_의 메모리를 해제하는 소멸자를 반드시 정의할 것
[헤맨 곳]
1. inventory class를 정의한 뒤 main.cpp에서 Inventory<Item> i(3);를 통해 메모리 할당 및 선언을 하려고 했는데, 오류가 발생했다.
이는 기본 생성자가 정의되어있지 않았기 때문에 생긴 일이었다.
아까 정의한 생성자에서 디폴트 값만 추가해준다.
class Item
{
public:
Item(std::string name = "", int price = 0);
void PrintInfo() const;
private:
std::string name_;
int price_;
};
항상 디폴트 값을 신경쓸 것.
3. [4번 과제] C++ Summary - 연금술 공방 관리 시스템 구현
이미 존재하는 코드를 해석하고 수정하는 과제이다.
기존 코드 분석:
어떤 의도로 이 코드를 구현했을까?
연금술 레시피를 작성하고 목록에 추가하여 확인할 수 있는 시스템을 구현하려고 했다.
수정을 해야 한다면, 기존 코드의 수정을 최소화 할 수 있는 방안이 있을까?
지금까지 배운 내용을 토대로, 기존의 코드를 수정하지 않고 새로운 코드를 추가하여 확장하는 방식으로 작성하면 된다.
기존 코드는 SOLID 원칙을 잘 준수하고 있나?
각 원칙을 잘 준수하고 있는지 확인해보자.
class Potion
class PotionRecipe{
public:
std::string potionName;
std::vector<std::string> ingredients;
PotionRecipe(const std::string& name, const std::vector<std::string>& ingredients);
};
/*
분석
포션 이름과 필요 재료를 저장하는 class
*/
1. 단일 책임 원칙(SRP)
각 클래스는 하나의 책임만 가져야 한다.
-> 포션 레시피를 저장하는 기능 하나만 있으므로 ok
2. 개방 폐쇄 원칙(OCP)
확장에는 열려 있어야 하고, 수정에는 닫혀 있어야 한다.
-> 변수가 public으로 선언되어 있어 private으로 바꾸고 get/set 함수를 만들어주는 것이 좋을 것 같다.
3. 리스 코프 치환 원칙(LSP)
자식 클래스는 부모 클래스에서 기대되는 행동을 보장해야 한다.
-> 이 코드에서는 상속 관계가 없으므로 ok
4. 인터페이스 분리 원칙(ISP)
클라이언트는 자신이 사용하지 않는 메서드에 의존하지 않아야 한다.
역할별로 세분화된 인터페이스를 만들어야 한다.
-> 생성자와 변수만 존재하므로 ok
5. 의존 역전 원칙(DIP)
고수준 모듈은 저 수준 모듈에 직접 의존하는 것이 아니라, 두 모듈 모두 추상화에 의존해야 한다.
-> 코드를 그대로 올릴 수 없어서 선언문만 올려놨지만 실제 코드는 선언과 동시에 정의하고 있으므로 분리시키는 것이 좋을 것 같다.
class AlchemyWorkshop
// AlchemyWorkshop 클래스: 레시피 목록을 관리
class AlchemyWorkshop {
private:
std::vector<PotionRecipe> recipes;
public:
// addRecipe 메서드: 재료 목록(vector)을 매개변수로 받도록 수정
void addRecipe(const std::string& name, const std::vector<std::string>& ingredients) {
recipes.push_back(PotionRecipe(name, ingredients));
std::cout << ">> 새로운 레시피 '" << name << "'이(가) 추가되었습니다." << std::endl;
}
// 모든 레시피 출력 메서드
void displayAllRecipes() const {
if (recipes.empty()) {
std::cout << "아직 등록된 레시피가 없습니다." << std::endl;
return;
}
std::cout << "\n--- [ 전체 레시피 목록 ] ---" << std::endl;
for (size_t i = 0; i < recipes.size(); ++i) {
std::cout << "- 물약 이름: " << recipes[i].potionName << std::endl;
std::cout << " > 필요 재료: ";
// 재료 목록을 순회하며 출력
for (size_t j = 0; j < recipes[i].ingredients.size(); ++j) {
std::cout << recipes[i].ingredients[j];
// 마지막 재료가 아니면 쉼표로 구분
if (j < recipes[i].ingredients.size() - 1) {
std::cout << ", ";
}
}
std::cout << std::endl;
}
std::cout << "---------------------------\n";
}
};
1. 단일 책임 원칙(SRP)
각 클래스는 하나의 책임만 가져야 한다.
-> 레시피 목록을 추가하는 기능과 출력하는 기능이 함께 있다. 분리할 필요가 있을듯.
2. 개방 폐쇄 원칙(OCP)
확장에는 열려 있어야 하고, 수정에는 닫혀 있어야 한다.
-> 선언과 정의를 함께 하고 있으므로 분리해줘야 한다. 헤더 파일과 cpp파일로 나누어서 구현하면 될 듯.
3. 리스 코프 치환 원칙(LSP)
자식 클래스는 부모 클래스에서 기대되는 행동을 보장해야 한다.
-> 이 코드에서는 상속 관계가 없으므로 ok
4. 인터페이스 분리 원칙(ISP)
클라이언트는 자신이 사용하지 않는 메서드에 의존하지 않아야 한다.
역할별로 세분화된 인터페이스를 만들어야 한다.
-> 앞에서 이야기했듯이 addRecipe()와 displayAllRecipes() 함수를 각각 추상 클래스로 분리해서 인터페이스를 만들면 될 듯.
5. 의존 역전 원칙(DIP)
고수준 모듈은 저 수준 모듈에 직접 의존하는 것이 아니라, 두 모듈 모두 추상화에 의존해야 한다.
-> 추상화한 클래스를 AlchemyWorkshop 클래스로 사용하면 될 것 같다.
주어진 코드 스니펫을 SOLID 원칙에 맞게 수정해보고 과제를 수행하자.
더 공부해볼 점
solid 원칙에 따라서 class와 메서드를 분리하여 구현하는 게 아직 어렵다. 익숙해질 때까지 반복해보기.
여러 클래스와 메서드가 #include를 통해 소통하고 인수를 주고받는 것을 자세히 탐구할 것.
'Unreal5 공부 > TIL' 카테고리의 다른 글
| 2026/03/26 TIL (0) | 2026.03.26 |
|---|---|
| 2026/03/25 TIL (0) | 2026.03.25 |
| 2026/03/23 TIL (1) | 2026.03.23 |
| 2026/03/20 TIL (0) | 2026.03.20 |
| 2026/03/19 TIL (0) | 2026.03.19 |