icon안동민 개발노트

클래스와 객체의 개념


객체 지향 프로그래밍 (OOP) 소개

 객체 지향 프로그래밍(Object-Oriented Programming, OOP)은 현대 소프트웨어 개발에서 가장 중요한 패러다임 중 하나입니다.

 OOP는 실제 세계의 객체를 모델링하여 프로그램을 구조화하는 방식으로, 코드의 재사용성, 유지보수성, 확장성을 크게 향상시킵니다.

 OOP의 주요 특징

 1. 캡슐화 (Encapsulation)

  • 데이터와 이를 처리하는 함수를 하나의 단위로 묶음
  • 데이터 은닉을 통해 객체의 내부 구현을 숨기고 외부 인터페이스만 제공

 2. 상속 (Inheritance)

  • 기존 클래스의 특성을 새로운 클래스가 물려받음
  • 코드 재사용성 증가 및 계층적 관계 표현 가능

 3. 다형성 (Polymorphism)

  • 동일한 인터페이스로 다양한 객체를 다룰 수 있음
  • 런타임에 객체의 실제 타입에 따라 적절한 메서드 호출

 4. 추상화 (Abstraction)

  • 복잡한 시스템을 간단한 인터페이스로 표현
  • 필수적인 정보만 표현하여 복잡성 감소

클래스란?

 클래스는 객체를 생성하기 위한 템플릿 또는 청사진입니다.

 데이터(속성)와 함수(메서드)를 하나의 단위로 묶어 새로운 데이터 타입을 정의합니다.

 클래스의 구조

class ClassName {
private:
    // private 멤버 변수들
    // private 멤버 함수들
 
public:
    // public 멤버 변수들
    // public 멤버 함수들
 
protected:
    // protected 멤버 변수들
    // protected 멤버 함수들
};

 예제 : 간단한 Car 클래스

class Car {
private:
    std::string brand;
    int year;
    double price;
 
public:
    // 생성자
    Car(const std::string& b, int y, double p) : brand(b), year(y), price(p) {}
 
    // Getter 메서드들
    std::string getBrand() const { return brand; }
    int getYear() const { return year; }
    double getPrice() const { return price; }
 
    // Setter 메서드들
    void setBrand(const std::string& b) { brand = b; }
    void setYear(int y) { year = y; }
    void setPrice(double p) { price = p; }
 
    // 기타 메서드
    void displayInfo() const {
        std::cout << year << " " << brand << " ($" << price << ")" << std::endl;
    }
};

객체란?

 객체는 클래스의 인스턴스입니다.

 클래스를 바탕으로 메모리에 할당된 실제 데이터 구조를 의미합니다.

 객체 생성 및 사용 예제

int main() {
    // 객체 생성
    Car myCar("Toyota", 2023, 25000.0);
 
    // 객체의 메서드 호출
    myCar.displayInfo();  // 출력: 2023 Toyota ($25000)
 
    // Getter 메서드 사용
    std::cout << "Brand: " << myCar.getBrand() << std::endl;
 
    // Setter 메서드 사용
    myCar.setPrice(24000.0);
    myCar.displayInfo();  // 출력: 2023 Toyota ($24000)
 
    return 0;
}

클래스와 객체의 관계

 클래스와 객체의 관계는 '설계도'와 '실제 건물'의 관계와 유사합니다.

  • 클래스 : 객체의 구조와 행동을 정의하는 추상적인 개념
  • 객체 : 클래스를 기반으로 생성된 실체, 실제 메모리를 차지함

 하나의 클래스로부터 여러 개의 객체를 생성할 수 있으며, 각 객체는 독립적인 메모리 공간을 가집니다.

캡슐화의 개념

 캡슐화는 데이터와 이를 처리하는 함수를 하나의 단위로 묶는 것을 의미합니다.

 이는 데이터 은닉(data hiding)을 통해 구현되며, 객체의 내부 구현을 숨기고 외부에는 필요한 인터페이스만을 제공합니다.

 캡슐화의 장점

  1. 데이터 보호
  2. 유지보수성 향상
  3. 사용자 인터페이스 단순화

 예제 : 캡슐화를 적용한 BankAccount 클래스

class BankAccount {
private:
    double balance;
    std::string accountNumber;
 
    // 내부 사용 함수
    bool isValidAmount(double amount) const {
        return amount > 0;
    }
 
public:
    BankAccount(const std::string& accNum, double initialBalance = 0)
        : accountNumber(accNum), balance(initialBalance) {}
 
    void deposit(double amount) {
        if (isValidAmount(amount)) {
            balance += amount;
            std::cout << "Deposit successful. New balance: $" << balance << std::endl;
        } else {
            std::cout << "Invalid deposit amount." << std::endl;
        }
    }
 
    void withdraw(double amount) {
        if (isValidAmount(amount) && balance >= amount) {
            balance -= amount;
            std::cout << "Withdrawal successful. New balance: $" << balance << std::endl;
        } else {
            std::cout << "Invalid withdrawal amount or insufficient funds." << std::endl;
        }
    }
 
    double getBalance() const {
        return balance;
    }
 
    std::string getAccountNumber() const {
        return accountNumber;
    }
};

클래스와 구조체의 차이

 C++에서 클래스와 구조체는 매우 유사하지만, 몇 가지 중요한 차이가 있습니다.

  1. 기본 접근 지정자
  • 클래스 : private
  • 구조체 : public
  1. 상속
  • 클래스 : 기본적으로 private 상속
  • 구조체 : 기본적으로 public 상속
  1. 사용 목적
  • 클래스 : 데이터와 함수를 결합한 복잡한 데이터 타입
  • 구조체 : 주로 간단한 데이터 그룹화에 사용

클래스 설계 원칙

 1. 단일 책임 원칙 (Single Responsibility Principle)

  • 클래스는 하나의 책임만 가져야 함
  • 변경의 이유가 오직 하나여야 함

 2. 높은 응집도 (High Cohesion)

  • 클래스의 멤버들은 서로 밀접하게 관련되어야 함
  • 클래스의 목적과 관련 없는 기능은 다른 클래스로 분리

 3. 낮은 결합도 (Low Coupling)

  • 클래스 간의 상호의존성을 최소화
  • 한 클래스의 변경이 다른 클래스에 미치는 영향 최소화

실습 : 도서관 관리 시스템 클래스 설계

 도서관 관리 시스템의 일부로 BookLibrary 클래스를 설계해봅시다.

#include <iostream>
#include <string>
#include <vector>
 
class Book {
private:
    std::string title;
    std::string author;
    std::string ISBN;
    bool available;
 
public:
    Book(const std::string& t, const std::string& a, const std::string& i)
        : title(t), author(a), ISBN(i), available(true) {}
 
    std::string getTitle() const { return title; }
    std::string getAuthor() const { return author; }
    std::string getISBN() const { return ISBN; }
    bool isAvailable() const { return available; }
 
    void setAvailable(bool status) { available = status; }
 
    void displayInfo() const {
        std::cout << "Title: " << title << ", Author: " << author 
                  << ", ISBN: " << ISBN << ", Available: " 
                  << (available ? "Yes" : "No") << std::endl;
    }
};
 
class Library {
private:
    std::vector<Book> books;
 
public:
    void addBook(const Book& book) {
        books.push_back(book);
    }
 
    void displayAllBooks() const {
        for (const auto& book : books) {
            book.displayInfo();
        }
    }
 
    Book* findBook(const std::string& ISBN) {
        for (auto& book : books) {
            if (book.getISBN() == ISBN) {
                return &book;
            }
        }
        return nullptr;
    }
 
    bool borrowBook(const std::string& ISBN) {
        Book* book = findBook(ISBN);
        if (book && book->isAvailable()) {
            book->setAvailable(false);
            std::cout << "Book borrowed successfully." << std::endl;
            return true;
        }
        std::cout << "Book not available for borrowing." << std::endl;
        return false;
    }
 
    bool returnBook(const std::string& ISBN) {
        Book* book = findBook(ISBN);
        if (book && !book->isAvailable()) {
            book->setAvailable(true);
            std::cout << "Book returned successfully." << std::endl;
            return true;
        }
        std::cout << "Invalid book return." << std::endl;
        return false;
    }
};

연습 문제

  1. Circle 클래스를 설계하세요. 이 클래스는 반지름을 private 멤버로 가지고, 원의 넓이와 둘레를 계산하는 메서드를 포함해야 합니다.
  2. Student 클래스와 Course 클래스를 설계하세요. Student는 여러 개의 Course를 수강할 수 있어야 하며, 평균 성적을 계산할 수 있어야 합니다.
  3. BankAccount 클래스를 확장하여 SavingsAccountCheckingAccount 클래스를 만드세요. 각 클래스는 고유한 특성(예 : 이자율, 수수료)을 가져야 합니다.

 참고자료

  • Stroustrup, Bjarne. "The C++ Programming Language (4th Edition)"
  • Meyers, Scott. "Effective C++: 55 Specific Ways to Improve Your Programs and Designs"
  • C++ Reference : Classes
  • C++ Core Guidelines