icon안동민 개발노트

클래스 정의와 객체 생성


클래스 정의 기본 구조

 C++에서 클래스는 다음과 같은 기본 구조를 가집니다.

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

접근 지정자 (Access Specifiers)

  1. private : 클래스 내부에서만 접근 가능
  2. public : 어디서든 접근 가능
  3. protected : 해당 클래스와 파생 클래스에서 접근 가능

 참고 : 클래스의 기본 접근 지정자는 private입니다.

멤버 변수 (Data Members)

 멤버 변수는 클래스의 상태를 나타내는 변수들입니다.

class Person {
private:
    std::string name;
    int age;
    double height;
public:
    // 멤버 함수들...
};

멤버 함수 (Member Functions)

 멤버 함수는 클래스의 행동을 정의하는 함수들입니다.

class Person {
private:
    std::string name;
    int age;
public:
    void setName(const std::string& n) { name = n; }
    std::string getName() const { return name; }
    void setAge(int a) { age = a; }
    int getAge() const { return age; }
    void introduce() const {
        std::cout << "My name is " << name << " and I'm " << age << " years old." << std::endl;
    }
};

생성자 (Constructors)

 생성자는 객체를 초기화하는 특별한 멤버 함수입니다.

  1. 기본 생성자
  2. 매개변수가 있는 생성자
  3. 복사 생성자
  4. 이동 생성자 (C++ 11)
class Person {
private:
    std::string name;
    int age;
public:
    // 기본 생성자
    Person() : name(""), age(0) {}
    
    // 매개변수가 있는 생성자
    Person(const std::string& n, int a) : name(n), age(a) {}
    
    // 복사 생성자
    Person(const Person& other) : name(other.name), age(other.age) {}
    
    // 이동 생성자 (C++11)
    Person(Person&& other) noexcept : name(std::move(other.name)), age(other.age) {
        other.age = 0;
    }
};

소멸자 (Destructors)

 소멸자는 객체가 소멸될 때 호출되는 특별한 멤버 함수입니다.

class DynamicArray {
private:
    int* data;
    int size;
public:
    DynamicArray(int s) : size(s) {
        data = new int[size];
    }
    
    ~DynamicArray() {
        delete[] data;
    }
};

객체 생성

 객체는 스택 또는 힙에 생성할 수 있습니다.

스택에 객체 생성
// 스택에 객체 생성
 
Person p1;  // 기본 생성자 호출
Person p2("Alice", 30);  // 매개변수가 있는 생성자 호출
힙에 객체 생성
// 힙에 객체 생성
 
Person* p3 = new Person();
Person* p4 = new Person("Bob", 25);
 
// 사용 후
delete p3;
delete p4;

멤버 초기화 리스트 (Member Initializer List)

 멤버 초기화 리스트는 생성자에서 멤버 변수를 초기화하는 효율적인 방법입니다.

class Rectangle {
private:
    double width;
    double height;
public:
    Rectangle(double w, double h) : width(w), height(h) {}
};

위임 생성자 (Delegating Constructors) (C++ 11)

 위임 생성자를 사용하면 다른 생성자를 호출하여 중복 코드를 줄일 수 있습니다.

class Person {
private:
    std::string name;
    int age;
public:
    Person(const std::string& n, int a) : name(n), age(a) {}
    Person() : Person("", 0) {}  // 위임 생성자
    Person(const std::string& n) : Person(n, 0) {}  // 위임 생성자
};

복사 생성자 (Copy Constructor)

 복사 생성자는 기존 객체를 이용해 새 객체를 생성할 때 사용됩니다.

class MyClass {
private:
    int* data;
public:
    MyClass(int d) : data(new int(d)) {}
    
    // 복사 생성자
    MyClass(const MyClass& other) : data(new int(*other.data)) {}
    
    ~MyClass() { delete data; }
};

이동 생성자 (Move Constructor) (C++ 11)

 이동 생성자는 리소스 소유권을 이전할 때 사용됩니다.

class MyClass {
private:
    int* data;
public:
    MyClass(int d) : data(new int(d)) {}
    
    // 이동 생성자
    MyClass(MyClass&& other) noexcept : data(other.data) {
        other.data = nullptr;
    }
    
    ~MyClass() { delete data; }
};

정적 멤버 (Static Members)

 정적 멤버는 클래스의 모든 객체가 공유하는 멤버입니다.

class Counter {
private:
    static int count;  // 선언
public:
    Counter() { ++count; }
    static int getCount() { return count; }
};
 
int Counter::count = 0;  // 정의

const 멤버 함수

 const 멤버 함수는 객체의 상태를 변경하지 않는 함수입니다.

class Circle {
private:
    double radius;
public:
    Circle(double r) : radius(r) {}
    double getArea() const { return 3.14 * radius * radius; }
};

실습 : 도서관 관리 시스템

 다음은 도서관 관리 시스템의 일부를 구현한 예제입니다.

#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) {}
 
    // Getter 메서드들
    std::string getTitle() const { return title; }
    std::string getAuthor() const { return author; }
    std::string getISBN() const { return ISBN; }
    bool isAvailable() const { return available; }
 
    // Setter 메서드
    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;
    static int totalBooks;  // 정적 멤버 변수
 
public:
    // 책 추가 메서드
    void addBook(const Book& book) {
        books.push_back(book);
        ++totalBooks;
    }
 
    // 모든 책 정보 출력 메서드
    void displayAllBooks() const {
        for (const auto& book : books) {
            book.displayInfo();
        }
    }
 
    // ISBN으로 책 검색 메서드
    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;
    }
 
    // 총 책 수 반환 메서드 (정적 메서드)
    static int getTotalBooks() {
        return totalBooks;
    }
};
 
// 정적 멤버 변수 초기화
int Library::totalBooks = 0;
 
int main() {
    Library myLibrary;
 
    // 책 추가
    myLibrary.addBook(Book("The C++ Programming Language", "Bjarne Stroustrup", "978-0321563842"));
    myLibrary.addBook(Book("Effective Modern C++", "Scott Meyers", "978-1491903996"));
 
    // 모든 책 정보 출력
    std::cout << "All books in the library:" << std::endl;
    myLibrary.displayAllBooks();
 
    // 책 대출
    myLibrary.borrowBook("978-0321563842");
 
    // 책 정보 다시 출력
    std::cout << "\nAfter borrowing a book:" << std::endl;
    myLibrary.displayAllBooks();
 
    // 총 책 수 출력
    std::cout << "\nTotal number of books: " << Library::getTotalBooks() << std::endl;
 
    return 0;
}

연습 문제

  1. BankAccount 클래스를 설계하세요. 이 클래스는 계좌 번호, 소유자 이름, 잔액을 private 멤버로 가지고, 입금, 출금, 잔액 조회 기능을 public 메서드로 제공해야 합니다.
  2. Date 클래스를 구현하세요. 이 클래스는 년, 월, 일을 표현하고, 날짜를 설정하고 조회하는 메서드를 제공해야 합니다. 또한, 윤년을 고려하여 유효한 날짜인지 확인하는 기능도 구현하세요.
  3. String 클래스를 직접 구현해보세요. 이 클래스는 문자열을 동적으로 할당하고, 복사 생성자와 이동 생성자를 포함해야 합니다. 또한, 문자열 연결, 부분 문자열 추출 등의 기능을 제공해야 합니다.


참고 자료

  • Stroustrup, Bjarne. "The C++ Programming Language (4th Edition)"
  • Meyers, Scott. "Effective Modern C++ : 42 Specific Ways to Improve Your Use of C++11 and C++14"
  • Sutter, Herb. "Exceptional C++ : 47 Engineering Puzzles, Programming Problems, and Solutions"
  • C++ Reference : Classes
  • ISO C++ Core Guidelines : Classes and Class Hierarchies