본문으로 건너뛰기
Previous
Next
C++ Classes and Objects: Constructors, Access Control,

C++ Classes and Objects: Constructors, Access Control,

C++ Classes and Objects: Constructors, Access Control,

이 글의 핵심

A class defines a blueprint; objects are the instances you create from it. This guide walks through C++ class fundamentals — constructors, encapsulation, destructors, and copy semantics — with complete working examples.

Class as Blueprint

A class defines the structure and behavior of a type. An object is a specific instance of that class — one particular entity created from the blueprint.

class   = blueprint  (defines once what the type is)
object  = instance   (you can create as many as you need)

The same class can produce thousands of objects, each with its own data, but all sharing the same behavior.


Your First Class

#include <iostream>
#include <string>

class Person {
public:
    std::string name;
    int age;

    void introduce() const {
        std::cout << "Hi, I'm " << name
                  << " and I'm " << age << " years old.\n";
    }
};

int main() {
    Person alice;       // create object on the stack
    alice.name = "Alice";
    alice.age = 25;
    alice.introduce();  // Hi, I'm Alice and I'm 25 years old.

    Person bob;
    bob.name = "Bob";
    bob.age = 30;
    bob.introduce();    // Hi, I'm Bob and I'm 30 years old.
}

alice and bob are separate objects — each has its own name and age, but both share the introduce() method defined in the class.


Constructors

A constructor is a special function that runs automatically when an object is created. It has the same name as the class and no return type.

class Rectangle {
public:
    double width;
    double height;

    // Default constructor — no arguments
    Rectangle() : width(0), height(0) {}

    // Parameterized constructor
    Rectangle(double w, double h) : width(w), height(h) {}

    double area() const {
        return width * height;
    }

    double perimeter() const {
        return 2 * (width + height);
    }
};

int main() {
    Rectangle r1;           // uses default constructor: width=0, height=0
    Rectangle r2(5.0, 3.0); // uses parameterized: width=5, height=3

    std::cout << r2.area() << '\n';       // 15
    std::cout << r2.perimeter() << '\n';  // 16
}

Member Initializer List

Prefer the initializer list (: member(value)) over assignment in the body. It’s more efficient and required for const members and references:

class Point {
    const int x_;  // const member — must use initializer list
    const int y_;
public:
    Point(int x, int y) : x_(x), y_(y) {}  // correct

    // Wrong — can't assign to const in body:
    // Point(int x, int y) { x_ = x; y_ = y; }
};

Access Control: public and private

Encapsulation means hiding the internal state and only exposing a controlled interface. Use private for data members and public for methods:

class BankAccount {
private:
    std::string owner_;
    double balance_;

public:
    BankAccount(const std::string& owner, double initial)
        : owner_(owner), balance_(initial) {}

    void deposit(double amount) {
        if (amount > 0) {
            balance_ += amount;
        }
    }

    bool withdraw(double amount) {
        if (amount > 0 && amount <= balance_) {
            balance_ -= amount;
            return true;
        }
        return false;
    }

    double getBalance() const { return balance_; }
    const std::string& getOwner() const { return owner_; }
};

int main() {
    BankAccount account("Alice", 1000.0);

    account.deposit(500.0);
    account.withdraw(200.0);

    std::cout << account.getBalance() << '\n';  // 1300

    // account.balance_ = -9999;  // compile error — private!
}

Why encapsulation?

  • The class controls what state is valid (no negative balance)
  • You can change the internal representation later without breaking callers
  • Users of the class only need to understand the public interface

const Member Functions

A const member function promises not to modify the object’s state. Mark getters as const:

class Circle {
    double radius_;
public:
    explicit Circle(double r) : radius_(r) {}

    double radius() const { return radius_; }  // const — just reads
    double area() const { return 3.14159 * radius_ * radius_; }  // const

    void setRadius(double r) {                  // non-const — modifies
        if (r >= 0) radius_ = r;
    }
};

void printInfo(const Circle& c) {   // takes const reference
    std::cout << "Radius: " << c.radius() << '\n';  // OK — const method
    std::cout << "Area: " << c.area() << '\n';      // OK — const method
    // c.setRadius(5);  // compile error — cannot call non-const on const
}

Destructors

A destructor runs automatically when an object goes out of scope (or is deleted). It’s the place to release resources:

class FileWriter {
    FILE* file_;
public:
    explicit FileWriter(const char* path) {
        file_ = fopen(path, "w");
        if (!file_) throw std::runtime_error("Cannot open file");
    }

    ~FileWriter() {         // destructor — called automatically
        if (file_) {
            fclose(file_);  // release the resource
        }
    }

    void write(const char* text) {
        fputs(text, file_);
    }
};

int main() {
    {
        FileWriter writer("output.txt");
        writer.write("Hello\n");
    }  // writer goes out of scope — destructor runs, file closed automatically
}

This pattern — acquiring resources in the constructor and releasing them in the destructor — is called RAII (Resource Acquisition Is Initialization). It is the fundamental C++ idiom for preventing resource leaks.


Shallow Copy vs Deep Copy

When a class owns a raw pointer, the default copy behavior (shallow copy) copies the pointer value — two objects end up pointing to the same memory:

class Buffer {
    int* data_;
    int size_;
public:
    Buffer(int size) : size_(size), data_(new int[size]) {}

    ~Buffer() { delete[] data_; }

    // Default copy — copies the pointer, NOT the data
};

int main() {
    Buffer b1(10);
    Buffer b2 = b1;  // both b1.data_ and b2.data_ point to the SAME array

}  // b1 and b2 both try to delete[] the same array — double-free crash!

Fix option 1: Rule of Three — define copy constructor and copy assignment:

class Buffer {
    int* data_;
    int size_;
public:
    Buffer(int size) : size_(size), data_(new int[size]) {}

    // Copy constructor — deep copy
    Buffer(const Buffer& other) : size_(other.size_), data_(new int[other.size_]) {
        std::copy(other.data_, other.data_ + size_, data_);
    }

    // Copy assignment
    Buffer& operator=(const Buffer& other) {
        if (this != &other) {
            delete[] data_;
            size_ = other.size_;
            data_ = new int[size_];
            std::copy(other.data_, other.data_ + size_, data_);
        }
        return *this;
    }

    ~Buffer() { delete[] data_; }
};

Fix option 2: Rule of Zero — use standard containers (preferred):

class Buffer {
    std::vector<int> data_;  // vector handles copy/move/destroy automatically
public:
    explicit Buffer(int size) : data_(size) {}
    // No destructor, copy constructor, or assignment operator needed
};

Prefer Rule of Zero: let std::vector, std::string, and std::unique_ptr handle resource management. Only write Rule of Three/Five when you genuinely need to manage a raw resource.


struct vs class

In C++, struct and class are nearly identical — the only difference is default access:

struct Point {     // default: public
    int x, y;
    Point(int x, int y) : x(x), y(y) {}
};

class PrivatePoint {  // default: private
    int x, y;
public:
    PrivatePoint(int x, int y) : x(x), y(y) {}
    int getX() const { return x; }
};

Common convention:

  • struct for plain data aggregates (no invariants, all public)
  • class for objects with behavior and private state that needs protection

Complete Example: Student Grade Tracker

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

class Student {
    std::string name_;
    std::vector<double> grades_;

public:
    explicit Student(const std::string& name) : name_(name) {}

    void addGrade(double grade) {
        if (grade >= 0 && grade <= 100) {
            grades_.push_back(grade);
        }
    }

    double average() const {
        if (grades_.empty()) return 0.0;
        double sum = std::accumulate(grades_.begin(), grades_.end(), 0.0);
        return sum / grades_.size();
    }

    char letterGrade() const {
        double avg = average();
        if (avg >= 90) return 'A';
        if (avg >= 80) return 'B';
        if (avg >= 70) return 'C';
        if (avg >= 60) return 'D';
        return 'F';
    }

    void printReport() const {
        std::cout << name_ << ": "
                  << average() << "% ("
                  << letterGrade() << ")\n";
    }

    const std::string& name() const { return name_; }
};

int main() {
    Student alice("Alice");
    alice.addGrade(92);
    alice.addGrade(88);
    alice.addGrade(95);
    alice.printReport();  // Alice: 91.667% (A)

    Student bob("Bob");
    bob.addGrade(72);
    bob.addGrade(68);
    bob.addGrade(75);
    bob.printReport();    // Bob: 71.667% (C)
}

Key Takeaways

  • A class is a blueprint; objects are instances created from it
  • Constructors initialize objects; use member initializer lists for efficiency
  • private hides state; public exposes the interface — this is encapsulation
  • const member functions promise not to modify the object — mark all getters as const
  • Destructors run automatically when objects go out of scope — use RAII to release resources
  • Shallow copy of a raw pointer causes double-free — use smart pointers or implement the Rule of Three/Five
  • Prefer Rule of Zero: let std::vector, std::string, and smart pointers manage resources automatically

자주 묻는 질문 (FAQ)

Q. 이 내용을 실무에서 언제 쓰나요?

A. Learn C++ OOP from scratch: classes, constructors, public/private access, destructors, const member functions, and the R… 실무에서는 위 본문의 예제와 선택 가이드를 참고해 적용하면 됩니다.

Q. 선행으로 읽으면 좋은 글은?

A. 각 글 하단의 이전 글 또는 관련 글 링크를 따라가면 순서대로 배울 수 있습니다. C++ 시리즈 목차에서 전체 흐름을 확인할 수 있습니다.

Q. 더 깊이 공부하려면?

A. cppreference와 해당 라이브러리 공식 문서를 참고하세요. 글 말미의 참고 자료 링크도 활용하면 좋습니다.


같이 보면 좋은 글 (내부 링크)

이 주제와 연결되는 다른 글입니다.


이 글에서 다루는 키워드 (관련 검색어)

C++, class, object, OOP, beginner 등으로 검색하시면 이 글이 도움이 됩니다.