[CH2/04] C++ Summary

김여울·2025년 6월 11일

내일배움캠프

목록 보기
19/139

C++ Summary

요구사항

필수 기능 가이드

기존 도서관 관리 프로그램에 검색 기능을 추가해주세요

  • 책 제목으로 검색이 가능해야 합니다.
  • 작가로 검색이 가능해야 합니다.
  • 책 제목이 동일한 경우는 없다고 가정 합니다.

필수 기능 구현 완료 후 전체적인 구조를 그리면 아래와 같습니다.
어디까지나 참조일 뿐 꼭 이대로 구현할 필요는 없습니다.

도전 기능 가이드

기존 도서관 관리 프로그램에 필수 기능을 추가한 상태에서 아래 대여 기능을 추가해주세요

  • 특정 책의 대여 여부를 알 수 있어야 합니다.
  • 책의 이름으로 대여 여부를 검색하고 대여가 아닌 경우 대여할 수 있어야 합니다.
  • 책의 작가로 대여 여부를 검색하고 대여가 아닌 경우 대여할 수 있어야 합니다.
  • 책을 반납할 수 있어야 합니다.
  • 모든 책의 재고는 난이도를 낮추기 위해 3권으로 통일 합니다.

도전 기능 구현까지 완료한 후 전체적인 구조를 그리면 아래와 같습니다.
어디까지나 참조일 뿐 꼭 이대로 구현할 필요는 없습니다.

1️⃣ 검색 기능 추가

  • 책 제목과 작가로 책을 검색할 수 있도록 한다
  • 제목 또는 작가로 검색하면 해당 책이 있는지 찾아서 출력한다

2️⃣ 대여 기능 추가

  • 각 책마다 재고(3권)를 관리하고, 책의 대여 여부를 추적한다
  • 책이 대여 중이 아니라면 대여하고, 대여가 되면 재고를 1권 감소한다
  • 반납 기능도 필요


코드

#include <iostream>
#include <vector>
#include <string>

using namespace std; // namespace std 사용

class Book {
public:
    string title;
    string author;
    int stock;       // 책 재고
    
    Book(const string& title, const string& author)
        : title(title), author(author), stock(3) {
    }

    // 대여 기능
    bool rentBook() 
    {
        if (stock > 0)  // 재고 있으면 대여 가능
        {
            stock--;    // 대여 시 재고 1권 감소
            return true;
        }
        return false;   // 재고 없으면 대여 불가
    }

    // 반납 기능
    void returnBook()
    {
        stock++;    // 반납 시 재고 1권 증가
    }
    
};

class BookManager {
private:
    vector<Book> books; // 책 목록 저장

public:
    // 책 추가 메서드
    // 책 제목, 저자를 매개변수로 받음
    // 문자열 상수와 참조로 받음 -> 값 변경 방지, 메모리 최적화
    void addBook(const string& title, const string& author) { 
        books.push_back(Book(title, author)); // push_back 사용해 책 추가
        cout << "책이 추가되었습니다: " << title << " by " << author << endl;
    }

    // 모든 책 출력 메서드
    void displayAllBooks() const {
        if (books.empty()) {
            cout << "현재 등록된 책이 없습니다." << endl;
            return;
        }

        cout << "현재 도서 목록:" << endl;
        for (size_t i = 0; i < books.size(); i++) { // 일반적인 for문 사용
            cout << "- " << books[i].title << " by " << books[i].author << endl;
        }
    }

    // 책 검색
    void searchBookByTitle(const string& title) 
    {
        bool found = false; // 아직 책을 못 찾은 상태
       
        // books.size()는 books에 들어있는 원소(책)의 개수를 반환하는 함수
        for (size_t i = 0; i < books.size(); i++)
        {
            if (books[i].title == title)    // i번째 책 제목이 내가 찾는 제목과 일치
            {
                cout << "책 제목: " << books[i].title << " 작가: " << books[i].author;
                cout << " 재고: " << books[i].stock << "권" << endl;
                found = true;   // for문 돌면서 책 찾으면 true
                break;
            }
        }

        if (!found)
        {
            cout << "해당 제목의 책을 찾을 수 없습니다." << endl;
        }
    }

    // 책 대여
    void rentBookByTitle(const string& title)
    {
        for (size_t i = 0; i < books.size(); i++)
        {
            if (books[i].title == title)    // i번째 책 제목이 내가 찾는 제목과 일치
            {
                if (books[i].rentBook())
                {
                    cout << "책 '" << title << "' 대여가 완료되었습니다." << endl;
                }
                else 
                {
                    cout << "책 '" << title << "'은 대여할 수 없습니다." << endl;  // 재고부족
                }

                return; // 함수 종료, 반환값 없음
            }
        }

        // for문을 다 돌았는데 return이 안 됐으면 책이 없는 것
        cout << "해당 제목의 책을 찾을 수 없습니다." << endl;
    }

    // 책 반납
    void returnBookByTitle(const string& title)
    {
        for (size_t i = 0; i < books.size(); i++)
        {
            if (books[i].title == title)
            {
                books[i].returnBook();
                cout << "책 '" << title << "'이 반납되었습니다." << endl;
                return;
            }
        }
        cout << "해당 제목의 책을 찾을 수 없습니다." << endl;
    }
};

int main() 
{
    BookManager manager;

    // 도서관 관리 프로그램의 기본 메뉴를 반복적으로 출력하여 사용자 입력을 처리합니다.
    // 프로그램 종료를 선택하기 전까지 계속 동작합니다.
    while (true) 
    {
        cout << "\n도서관 관리 프로그램" << endl;
        cout << "1. 책 추가" << endl; // 책 정보를 입력받아 책 목록에 추가
        cout << "2. 모든 책 출력" << endl; // 현재 책 목록에 있는 모든 책 출력
        cout << "3. 제목으로 책 검색" << endl;
        cout << "4. 책 대여" << endl;
        cout << "5. 책 반납" << endl;
        cout << "6. 종료" << endl; // 프로그램 종료
        cout << "선택: ";

        int choice; // 사용자의 메뉴 선택을 저장
        cin >> choice;

        if (choice == 1) 
        {
            // 1번 선택: 책 추가
            // 사용자로부터 책 제목과 저자명을 입력받아 BookManager에 추가합니다.
            string title, author;   // 책 제목, 저장명 저장할 변수 선언
            cout << "책 제목: ";
            cin.ignore(); // 이전 입력의 잔여 버퍼를 제거 -> 새로운 입력 받을 준비
            getline(cin, title); // 제목 입력 (공백 포함) 받아 title에 저장
            cout << "책 저자: ";
            getline(cin, author); // 저자명 입력 (공백 포함) 받아 author에 저장
            manager.addBook(title, author); // 입력받은 책 정보를 추가
        }
        else if (choice == 2) 
        {
            // 2번 선택: 모든 책 출력
            // 현재 BookManager에 저장된 책 목록을 출력합니다.
            manager.displayAllBooks();
        }
        else if (choice == 3)
        {
            // 3번 선택: 제목으로 책 검색
            string title;
            cout << "책 제목: ";
            cin.ignore();
            getline(cin, title);
            manager.searchBookByTitle(title);
        }
        else if (choice == 4)
        {
            // 4번 선택: 책 대여
            string title;
            cout << "책 제목: ";
            cin.ignore();
            getline(cin, title);
            manager.rentBookByTitle(title);
        }
        else if (choice == 5)
        {
            // 5번 선택: 책 반납
            string title;
            cout << "책 제목: ";
            cin.ignore();
            getline(cin, title);
            manager.returnBookByTitle(title);
        }
        else if (choice == 6) 
        {
            // 3번 선택: 종료
            // 프로그램을 종료하고 사용자에게 메시지를 출력합니다.
            cout << "프로그램을 종료합니다." << endl;
            break; // while 루프 종료
        }
        else 
        {
            // 잘못된 입력 처리
            // 메뉴에 없는 번호를 입력했을 경우 경고 메시지를 출력합니다.
            cout << "잘못된 입력입니다. 다시 시도하세요." << endl;
        }
    }

    return 0; // 프로그램 정상 종료
}


구현 기능 정리

검색 기능 추가

  • 제목이나 작가로 책을 찾을 수 있도록 searchBookByTitle()searchBookByAuthor() 함수 추가

대여 기능 추가

  • Book 클래스에 stock(재고) 변수를 추가해 책의 대여 상태를 추적
  • 대여 시 stock을 감소시키고, 반납 시 stock을 증가시킴

생성자 초기화 리스트

Book(const string& title, const string& author)
        : title(title), author(author), stock(3) {
    }
  • C++에서 생성자는 객체가 생성될 때 초기화 작업을 하는 함수
  • Book(const string& title, const string& author) : 생성자 선언
    • 이 생성자는 titleauthor 라는 매개변수를 받아서 객체의 멤버 변수들을 초기화함
  • title(title), author(author), stock(3), isRented(false) : 생성자 초기화 리스트
    • title(title) - 객체의 title 멤버 변수를 생성자의 매개변수 title로 초기화
    • author(author) - author 멤버 변수를 생성자의 매개변수 author로 초기화
    • stock(3) - stock 멤버 변수를 3으로 초기화
      → 기본값으로 3권이 있다고 설정하는 것

생성자 초기화 리스트 vs 멤버 초기화 리스트

생성자 초기화 리스트

  • 생성자에서 객체를 초기화할 때 사용
  • 생성자 초기화 리스트는 객체가 생성될 때 멤버 변수들을 설정
  • 위의 title, author, stock 가 생성자 초기화 리스트로 초기화 된 것
// 생성자 초기화 리스트 X
class Book {
private:
    int stock;
public:
    Book(int s) {  // 생성자
        stock = s;  // 멤버 변수에 대입
    }
};

// 생성자 초기화 리스트 O
class Book {
private:
    int stock;
public:
    Book(int s) : stock(s) {  // 초기화 리스트
        // 생성자 본문은 비워두거나 추가 로직을 넣을 수 있음
    }
};

멤버 초기화 리스트

  • 클래스 내부에서 멤버 변수를 선언할 때 기본값을 지정하는 방법
  • 생성자에서 값을 따로 초기화하지 않으면 멤버 초기화 리스트에서 지정한 기본값이 사용됨
    📎멤버 초기화 리스트 TIL
// 멤버 초기화 리스트 X
// 생성 → 기본값 → 대입
MyClass() {
   member = 10; // 생성자 호출 후 기본값이 먼저 설정된 뒤, 대입됨
}

// 멤버 초기화 리스트 O
MyClass() : member(10) {
   // 여기 오기 전에 이미 member가 10으로 초기화됨, 생성 → 초기화
}
};
구분생성자 본문에서 대입생성자 초기화 리스트
초기화 시점객체가 생성된 후에 값 할당 (기본값이 먼저 설정된 후)생성자 호출 시 바로 멤버 변수 초기화
초기화 방식생성자 내부에서 멤버 변수에 값을 대입생성자 호출 시 초기화 리스트에서 바로 값 대입
기본값 설정생성자 호출 후, 멤버 변수를 설정 가능클래스 내에서 멤버 변수를 선언할 때 기본값을 설정
초기화 시점의 차이점객체가 생성된 후, 기본값을 설정한 뒤 대입생성자 호출 시, 바로 멤버 변수 초기화
장점생성자 본문에서 로직을 작성하면서 초기화할 수 있음객체 생성 시 바로 초기화되므로 더 효율적이고 직관적임
사용 예시stock = 10;: stock(10)

rentBook(), returnBook()

  • 책 객체를 관리하기 위해서 Book 클래스 안에 구현
  • 클래스 외부에 두면 각각의 책 상태를 외부에서 추적해야함

void addBook(const string& title, const string& author)

  • const string& title, const string& author:
  • 매개변수(parameter) : 함수가 호출될 때 외부에서 값을 전달받는 역할
    • const string& title : title은 책 제목을 저장하는 매개변수
    • const : 이 매개변수가 함수 내부에서 변경되지 않게 함
      → 함수 내에서 title, author 값을 변경할 수 없음
    • string : 문자열 타입
      → 책 제목이나 저자명이 길면 stirng 객체의 크기가 커짐
      → title, author을 값으로 전달하면 성능 떨어질 수 있어 참조 사용
    • & : 참조(reference) - 메모리의 주소를 직접 전달해 복사 없이 원본 값을 변경할 수 있게 해줌
      → 값을 복사하지 않고 메모리에서 직접 접근해서 사용함 (메모리 사용 최적화)

books.size()

books.size()는 books에 들어있는 원소(책)의 개수를 반환하는 함수

size_t i = 0;

  • size_t
    • 주로 배열, 벡터 등의 크기나 인덱스를 표현할 때 사용
    • 부호 없는 정수 타입(Unsigned Integer Type)
    • 템플릿이 아니라 표준 라이브러리에서 typedef(별칭)로 정의된 타입

if (books[i].title == title)

  • books : 여러 책(Book)이 들어있는 vector
  • i : for문에서 사용하는 인덱스 (0, 1, 2, ...)
    • books[i] : i번째 책을 의미함
    • books[i].title : i번째 책의 제목을 의미
  • if 조건문의 의미
    • books[i].title == title
      → "i번째 책의 제목이, 내가 찾으려는 제목과 같니?"
  • .(dot) 연산자
    • 멤버 접근 연산자
    • 구조체(struct)나 클래스(class)의 멤버 변수나 멤버 함수에 접근할 때 사용함

i번째 책 제목과 찾는 책 제목 일치?

if (books[i].title == title) 

책 제목이 일치할 때

  • if 조건이 참 : i번째 책의 제목이 내가 찾는 제목(title)과 같음
  • "찾는 책"을 발견한 상황

books[i].rentBook()

  • 그 Book 객체의 rentBook()이라는 함수를 실행한다는 뜻
  • "i번째 책의 rentBook() 함수를 실행한다"
  • 점 연산자로 객체의 멤버 변수나 멤버 함수에 접근함

재고가 없다는 건?

 bool rentBook() 
 {
     if (stock > 0)  // 재고 있으면 대여 가능
     {
         stock--;    // 대여 시 재고 1권 감소
         return true;
     }
     return false;   // 재고 없으면 대여 불가
 }

만약 rentBook() 이 false를 반환
→ 책 제목은 일치하지만 재고가 0이라서 더 이상 대여할 수 없다는 뜻입니다.

책이 아예 없는 경우와의 차이

만약 for문을 끝까지 돌았는데 books[i].title == title 이 한 번도 참이 아님
→ 아예 그런 제목의 책 자체가 없는 것

예시

인덱스(i)books[i].titlebooks[i].stock
0C++ 기초2
1파이썬 입문0
2블루프린트 마스터3

1️⃣ 사용자가 "파이썬 입문"을 찾는다
2️⃣ i=1 에서 books.title == "파이썬 입문" → 참!
3️⃣ 그런데 books.stock == 0 이므로 rentBook() 은 false를 반환 → 재고 부족

1️⃣ 사용자가 "블루프린트 기초"를 찾는다
2️⃣ 인덱스 0, 1, 2 모두 title이 "블루프린트 기초"가 아님 → 책 자체가 없음

정리

  • 책 제목이 일치 = if (books[i].title == title) 가 참일 때
  • 재고가 없다 = 책은 찾았지만, 그 책의 재고(stock)가 0일 때(rentBook() 가 false)
  • 책이 없다 = for문을 끝까지 돌았는데 한 번도 제목이 일치하지 않을 때

cin.ignore();

  • cin 을 사용할 때 이전에 입력한 값이 입력 버퍼에 남아있는 경우가 있음
  • 이전에 cin 으로 숫자나 다른 문자열을 입력받은 후 getline 을 사용하려면 입력 버퍼를 비워줘야 한다
  • 이전 입력의 잔여 데이터를 제거하고 새로운 입력을 받을 준비를 하기 위해 cin.ignore(); 를 사용

getline(cin, title);

// getline 함수 정의

getline(입력스트림, 저장변수);
  • getline() 함수는 사용자로부터 한 줄을 입력받고, 그 입력값을 title에 저장함
    • cin : 입력을 받는 스트림 객체
    • title : 입력받은 값을 저장할 변수

getline과 cin 차이점

  • cin

    • 공백을 만나면 입력을 중단하고 그 이전까지의 문자열을 저장
    • (예) The Great Gatsby를 cin >> title;로 입력받으면 title에는 The만 저장됨
  • getline

    • 공백을 포함한 전체 문자열을 읽어옴
    • The Great Gatsby 전체를 getline으로 읽어오면 공백을 포함한 제목이 title에 저장됨

클래스와 객체를 통한 함수 접근

  • 클래스 (Class) = 설계도
    • 데이터를 저장할 변수와 그 데이터를 처리하는 함수들을 정의함
    • (예) class BookManager { ... };
  • 객체 (Object)
    = 클래스를 기반으로 실제 메모리 공간을 할당한 인스턴스
    • 객체는 클래스를 바탕으로 생성됨
      → 그 클래스의 멤버 함수와 변수를 사용할 수 있음
    • (예) BookManager manager;

클래스 자체는 설계도로 사용되며, 실제 프로그램에서 함수나 변수를 호출하는 데 객체를 사용함

객체를 통해 클래스 내에서 정의된 함수(메서드)에 접근할 수 있음

BookManager manager;       // 객체 생성
manager.addBook("C++", "홍길동");  // 객체를 통해 메서드 호출

manager.addBook()manager 라는 객체를 통해 BookManager 클래스의 addBook 메서드에 접근함

➡ 메서드는 객체를 통해 호출하고 클래스 자체는 함수 호출에 직접 사용되지 않는다

0개의 댓글