챕터5. 실습 문제

2025. 3. 28. 00:07Programming Languages/C++

5.7 실습 문제

문제 1: 은행 계좌 시스템

다양한 유형의 은행 계좌를 구현하는 클래스 계층 구조를 설계하세요:

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

// 추상 기본 클래스
class Account {
protected:
    std::string accountNumber;
    std::string ownerName;
    double balance;
    
public:
    Account(const std::string& number, const std::string& name, double initialBalance)
        : accountNumber(number), ownerName(name), balance(initialBalance) {}
    
    // 가상 소멸자
    virtual ~Account() {}
    
    // 모든 계좌 유형에 공통적인 메서드
    virtual void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            std::cout << amount << "원 입금 완료" << std::endl;
        } else {
            std::cout << "유효하지 않은 금액입니다." << std::endl;
        }
    }
    
    // 순수 가상 함수 - 파생 클래스에서 구현해야 함
    virtual bool withdraw(double amount) = 0;
    
    // 계좌 정보 표시
    virtual void displayInfo() const {
        std::cout << "계좌번호: " << accountNumber << std::endl;
        std::cout << "소유자: " << ownerName << std::endl;
        std::cout << "잔액: " << balance << "원" << std::endl;
    }
    
    // 접근자 메서드
    double getBalance() const { return balance; }
    std::string getAccountNumber() const { return accountNumber; }
    std::string getOwnerName() const { return ownerName; }
};

// 일반 계좌
class SavingsAccount : public Account {
private:
    double interestRate;  // 연이율 (%)
    
public:
    SavingsAccount(const std::string& number, const std::string& name, 
                double initialBalance, double rate)
        : Account(number, name, initialBalance), interestRate(rate) {}
    
    // withdraw 구현
    bool withdraw(double amount) override {
        if (amount > 0 && balance >= amount) {
            balance -= amount;
            std::cout << amount << "원 출금 완료" << std::endl;
            return true;
        } else {
            std::cout << "잔액 부족 또는 유효하지 않은 금액" << std::endl;
            return false;
        }
    }
    
    // 저축 계좌 전용 메서드: 이자 계산
    void applyInterest() {
        double interest = balance * (interestRate / 100.0);
        balance += interest;
        std::cout << interest << "원의 이자가 추가되었습니다." << std::endl;
    }
    
    // 계좌 정보 표시 오버라이딩
    void displayInfo() const override {
        Account::displayInfo();
        std::cout << "계좌 유형: 저축 계좌" << std::endl;
        std::cout << "이자율: " << interestRate << "%" << std::endl;
    }
};

// 당좌 계좌 (마이너스 통장)
class CheckingAccount : public Account {
private:
    double overdraftLimit;  // 마이너스 한도
    
public:
    CheckingAccount(const std::string& number, const std::string& name, 
                 double initialBalance, double limit)
        : Account(number, name, initialBalance), overdraftLimit(limit) {}
    
    // withdraw 구현 - 마이너스 한도까지 출금 가능
    bool withdraw(double amount) override {
        if (amount > 0 && (balance + overdraftLimit) >= amount) {
            balance -= amount;
            std::cout << amount << "원 출금 완료";
            if (balance < 0) {
                std::cout << " (마이너스 잔액: " << balance << "원)";
            }
            std::cout << std::endl;
            return true;
        } else {
            std::cout << "출금 한도 초과 또는 유효하지 않은 금액" << std::endl;
            return false;
        }
    }
    
    // 계좌 정보 표시 오버라이딩
    void displayInfo() const override {
        Account::displayInfo();
        std::cout << "계좌 유형: 당좌 계좌" << std::endl;
        std::cout << "마이너스 한도: " << overdraftLimit << "원" << std::endl;
    }
};

// 은행 시스템 클래스
class Bank {
private:
    std::string name;
    std::vector<Account*> accounts;
    
public:
    Bank(const std::string& bankName) : name(bankName) {}
    
    ~Bank() {
        // 모든 계좌 메모리 해제
        for (Account* account : accounts) {
            delete account;
        }
    }
    
    // 새 계좌 추가
    void addAccount(Account* account) {
        accounts.push_back(account);
    }
    
    // 계좌 검색
    Account* findAccount(const std::string& accountNumber) {
        for (Account* account : accounts) {
            if (account->getAccountNumber() == accountNumber) {
                return account;
            }
        }
        return nullptr;
    }
    
    // 모든 계좌 정보 표시
    void displayAllAccounts() const {
        std::cout << "===== " << name << " 은행 계좌 목록 =====" << std::endl;
        for (size_t i = 0; i < accounts.size(); i++) {
            std::cout << "\n계좌 #" << (i + 1) << ":" << std::endl;
            accounts[i]->displayInfo();
        }
    }
};

int main() {
    Bank bank("C++ 은행");
    
    // 계좌 생성
    SavingsAccount* savings = new SavingsAccount("S123", "홍길동", 10000, 2.5);
    CheckingAccount* checking = new CheckingAccount("C456", "김철수", 2000, 5000);
    
    // 은행에 계좌 추가
    bank.addAccount(savings);
    bank.addAccount(checking);
    
    // 계좌 정보 표시
    bank.displayAllAccounts();
    
    // 계좌 조작
    std::cout << "\n===== 계좌 조작 =====" << std::endl;
    Account* account = bank.findAccount("S123");
    if (account) {
        account->deposit(5000);
        account->withdraw(3000);
        
        // 저축 계좌면 이자 적용
        SavingsAccount* savingsPtr = dynamic_cast<SavingsAccount*>(account);
        if (savingsPtr) {
            savingsPtr->applyInterest();
        }
    }
    
    account = bank.findAccount("C456");
    if (account) {
        account->deposit(1000);
        account->withdraw(7000);  // 마이너스 통장 활용
    }
    
    // 업데이트된 계좌 정보 표시
    std::cout << "\n===== 업데이트된 계좌 정보 =====" << std::endl;
    bank.displayAllAccounts();
    
    return 0;
}

문제 2: 도형 계층 구조 구현

다양한 도형(원, 직사각형, 삼각형 등)에 대한 계층 구조를 설계하고, 각 도형의 면적과 둘레를 계산하는 프로그램을 작성하세요.

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

// 추상 기본 클래스
class Shape {
protected:
    std::string name;
    
public:
    Shape(const std::string& n) : name(n) {}
    
    virtual ~Shape() {}
    
    virtual double area() const = 0;
    virtual double perimeter() const = 0;
    
    void printInfo() const {
        std::cout << "도형: " << name << std::endl;
        std::cout << "면적: " << area() << std::endl;
        std::cout << "둘레: " << perimeter() << std::endl;
    }
    
    std::string getName() const { return name; }
};

// 원 클래스
class Circle : public Shape {
private:
    double radius;
    
public:
    Circle(double r) : Shape("원"), radius(r) {}
    
    double area() const override {
        return M_PI * radius * radius;
    }
    
    double perimeter() const override {
        return 2 * M_PI * radius;
    }
    
    double getRadius() const { return radius; }
};

// 직사각형 클래스
class Rectangle : public Shape {
private:
    double width;
    double height;
    
public:
    Rectangle(double w, double h) : Shape("직사각형"), width(w), height(h) {}
    
    double area() const override {
        return width * height;
    }
    
    double perimeter() const override {
        return 2 * (width + height);
    }
    
    double getWidth() const { return width; }
    double getHeight() const { return height; }
};

// 정사각형 클래스 (직사각형 파생)
class Square : public Rectangle {
public:
    Square(double side) : Rectangle(side, side) {
        name = "정사각형";  // 이름 재정의
    }
};

// 삼각형 클래스
class Triangle : public Shape {
private:
    double a, b, c;  // 세 변의 길이
    
public:
    Triangle(double side1, double side2, double side3) 
        : Shape("삼각형"), a(side1), b(side2), c(side3) {
        
        // 삼각형 조건 검사
        if (!isValid()) {
            std::cout << "경고: 유효하지 않은 삼각형입니다." << std::endl;
        }
    }
    
    bool isValid() const {
        // 삼각형 부등식: 두 변의 합 > 나머지 한 변
        return (a + b > c) && (a + c > b) && (b + c > a);
    }
    
    double area() const override {
        if (!isValid()) return 0;
        
        // 헤론의 공식
        double s = (a + b + c) / 2;
        return std::sqrt(s * (s - a) * (s - b) * (s - c));
    }
    
    double perimeter() const override {
        return a + b + c;
    }
};

// 도형 관리 클래스
class ShapeManager {
private:
    std::vector<Shape*> shapes;
    
public:
    ~ShapeManager() {
        for (Shape* shape : shapes) {
            delete shape;
        }
    }
    
    void addShape(Shape* shape) {
        shapes.push_back(shape);
    }
    
    void printAllShapes() const {
        std::cout << "\n===== 모든 도형 정보 =====" << std::endl;
        for (size_t i = 0; i < shapes.size(); i++) {
            std::cout << "\n" << (i + 1) << ". ";
            shapes[i]->printInfo();
        }
    }
    
    double getTotalArea() const {
        double total = 0;
        for (const Shape* shape : shapes) {
            total += shape->area();
        }
        return total;
    }
};

int main() {
    ShapeManager manager;
    
    // 다양한 도형 추가
    manager.addShape(new Circle(5.0));
    manager.addShape(new Rectangle(4.0, 6.0));
    manager.addShape(new Square(5.0));
    manager.addShape(new Triangle(3.0, 4.0, 5.0));
    
    // 모든 도형 정보 출력
    manager.printAllShapes();
    
    // 전체 면적 계산
    std::cout << "\n모든 도형의 총 면적: " << manager.getTotalArea() << std::endl;
    
    return 0;
}

 

'Programming Languages > C++' 카테고리의 다른 글

포인터의 기본  (0) 2025.03.28
포인터와 참조  (0) 2025.03.28
다형성(Polymorphism)  (0) 2025.03.28
상속(Inheritance)  (0) 2025.03.28
객체 생성과 수명 주기  (0) 2025.03.28