Skip to Content
💻 코리아IT아카데미 신촌 - 프로그래밍 학습 자료
C++ 프로그래밍Unit 10: 클래스와 객체Topic 2: 캡슐화와 접근 제어

Topic 2: 캡슐화와 접근 제어 🔒

🎯 학습 목표

  • 캡슐화의 개념과 중요성을 이해할 수 있다
  • public, private, protected 접근 제어자의 차이를 설명할 수 있다
  • getter/setter 메서드를 적절히 활용할 수 있다
  • 정보 은닉을 통해 안전한 클래스를 설계할 수 있다

🏦 은행 금고로 이해하는 캡슐화

캡슐화를 이해하는 가장 쉬운 방법은 은행 금고를 생각해보는 것입니다! 🏦

은행 금고의 특징

  • 🔒 금고 내부: 돈과 중요한 서류 (private 데이터)
  • 🚪 금고 문: 특별한 열쇠나 비밀번호 필요 (접근 제어)
  • 👤 은행원: 정해진 절차로만 금고 접근 (public 메서드)
class BankVault { private: // 금고 내부 - 직접 접근 불가! double money; string secretDocument; public: // 은행원을 통한 접근 - 안전한 방법 void depositMoney(double amount); double withdrawMoney(double amount, string password); };

🔐 접근 제어자 완벽 이해

세 가지 접근 레벨

접근 제어자클래스 내부파생 클래스외부
public
protected
private

실생활 비유로 이해하기 🏠

class House { public: // 현관문 - 누구나 접근 가능 string address; void ringDoorbell() { cout << "딩동! 🔔" << endl; } protected: // 거실 - 가족과 친척만 접근 string familyPhoto; void watchTV() { cout << "TV 시청 중... 📺" << endl; } private: // 침실 - 나만 접근 가능 string diary; double hiddenMoney; void readDiary() { cout << "일기 읽는 중... 📔" << endl; } };

💡 실습: 스마트폰 클래스

#include <iostream> #include <string> using namespace std; class Smartphone { private: // 보호해야 할 중요한 정보들 string password; int batteryLevel; bool isLocked; string ownerName; public: // 생성자 - 초기 설정 Smartphone(string owner, string pwd) { ownerName = owner; password = pwd; batteryLevel = 100; isLocked = true; cout << ownerName << "님의 스마트폰이 생성되었습니다! 📱" << endl; } // 잠금 해제 - 비밀번호 확인 필요 bool unlock(string inputPassword) { if (inputPassword == password) { isLocked = false; cout << "✅ 잠금이 해제되었습니다!" << endl; return true; } else { cout << "❌ 비밀번호가 틀렸습니다!" << endl; return false; } } // 잠금 void lock() { isLocked = true; cout << "🔒 화면이 잠겼습니다." << endl; } // 앱 실행 - 잠금 해제 상태에서만 가능 void runApp(string appName) { if (!isLocked) { cout << "📱 " << appName << " 앱을 실행합니다!" << endl; batteryLevel -= 5; } else { cout << "❌ 먼저 잠금을 해제하세요!" << endl; } } // 배터리 확인 (getter) int getBatteryLevel() { return batteryLevel; } // 충전 (setter의 변형) void charge() { batteryLevel = 100; cout << "⚡ 충전 완료! 배터리: 100%" << endl; } // 상태 표시 void showStatus() { cout << "\n=== 📱 스마트폰 상태 ===" << endl; cout << "소유자: " << ownerName << endl; cout << "배터리: " << batteryLevel << "%" << endl; cout << "잠금 상태: " << (isLocked ? "잠김 🔒" : "해제 🔓") << endl; } }; int main() { // 스마트폰 생성 Smartphone myPhone("김철수", "1234"); // 상태 확인 myPhone.showStatus(); // 잠긴 상태에서 앱 실행 시도 myPhone.runApp("카카오톡"); // 틀린 비밀번호로 해제 시도 myPhone.unlock("0000"); // 올바른 비밀번호로 해제 myPhone.unlock("1234"); // 이제 앱 실행 가능 myPhone.runApp("카카오톡"); myPhone.runApp("유튜브"); // 배터리 확인 cout << "현재 배터리: " << myPhone.getBatteryLevel() << "%" << endl; // 충전 myPhone.charge(); // 다시 잠금 myPhone.lock(); myPhone.showStatus(); return 0; }

🎯 Getter와 Setter 패턴

왜 직접 접근하지 않을까? 🤔

class Student { private: int age; double gpa; public: // Getter - 값을 읽기 int getAge() const { // const: 이 함수는 멤버 변수를 바꾸지 않음 return age; } // Setter - 값을 설정 (유효성 검사 포함!) void setAge(int newAge) { if (newAge > 0 && newAge < 150) { age = newAge; } else { cout << "❌ 유효하지 않은 나이입니다!" << endl; } } // GPA getter double getGPA() const { return gpa; } // GPA setter - 범위 제한 void setGPA(double newGPA) { if (newGPA >= 0.0 && newGPA <= 4.5) { gpa = newGPA; } else { cout << "❌ GPA는 0.0 ~ 4.5 사이여야 합니다!" << endl; } } };

Getter/Setter의 장점

  1. 유효성 검사

    void setSpeed(int speed) { if (speed >= 0 && speed <= 200) { this->speed = speed; } }
  2. 계산된 속성 🧮

    double getAreaCircle() const { return 3.14 * radius * radius; // 저장하지 않고 계산해서 반환 }
  3. 접근 로그 📝

    int getSecretData() { cout << "[LOG] 민감한 데이터 접근!" << endl; return secretData; }

🏗️ 실전 예제: 게임 캐릭터 강화 시스템

#include <iostream> #include <string> using namespace std; class RPGCharacter { private: string name; int level; int hp; int maxHp; int attackPower; int exp; int expToNextLevel; // 레벨업 처리 (private 메서드) void checkLevelUp() { while (exp >= expToNextLevel) { exp -= expToNextLevel; level++; maxHp += 10; hp = maxHp; // 레벨업하면 HP 회복! attackPower += 5; expToNextLevel = level * 100; cout << "🎉 레벨 업! 현재 레벨: " << level << endl; cout << "💪 공격력 상승! 현재 공격력: " << attackPower << endl; } } public: // 생성자 RPGCharacter(string charName) { name = charName; level = 1; maxHp = 100; hp = maxHp; attackPower = 10; exp = 0; expToNextLevel = 100; cout << name << " 캐릭터가 생성되었습니다! ⚔️" << endl; } // 경험치 획득 void gainExp(int amount) { if (amount > 0) { exp += amount; cout << "✨ 경험치 " << amount << " 획득!" << endl; checkLevelUp(); // private 메서드 호출 } } // 데미지 받기 void takeDamage(int damage) { if (damage > 0) { hp -= damage; if (hp < 0) hp = 0; cout << "💥 " << damage << " 데미지를 받았습니다!" << endl; cout << "❤️ 남은 HP: " << hp << "/" << maxHp << endl; } } // HP 회복 void heal(int amount) { if (amount > 0) { hp += amount; if (hp > maxHp) hp = maxHp; cout << "💚 " << amount << " HP 회복!" << endl; cout << "❤️ 현재 HP: " << hp << "/" << maxHp << endl; } } // Getter 메서드들 string getName() const { return name; } int getLevel() const { return level; } int getHp() const { return hp; } int getAttackPower() const { return attackPower; } // 상태 표시 void showStatus() const { cout << "\n=== 캐릭터 정보 ===" << endl; cout << "이름: " << name << endl; cout << "레벨: " << level << endl; cout << "HP: " << hp << "/" << maxHp << endl; cout << "공격력: " << attackPower << endl; cout << "경험치: " << exp << "/" << expToNextLevel << endl; } }; int main() { RPGCharacter hero("용사"); hero.showStatus(); // 몬스터 사냥으로 경험치 획득 cout << "\n🐉 몬스터를 처치했습니다!" << endl; hero.gainExp(50); cout << "\n🐉 강한 몬스터를 처치했습니다!" << endl; hero.gainExp(80); // 레벨업! // 전투 중 데미지 hero.takeDamage(30); // 회복 hero.heal(20); hero.showStatus(); return 0; }

📋 캡슐화 체크리스트

✅ 좋은 캡슐화

  • 중요한 데이터는 private으로 보호
  • public 메서드로 안전한 접근 제공
  • 유효성 검사 포함
  • 의미 있는 메서드 이름

❌ 나쁜 캡슐화

  • 모든 멤버 변수가 public
  • getter/setter만 무작정 추가
  • 유효성 검사 없음
  • 내부 구현이 그대로 노출

💡 핵심 정리

  • 캡슐화: 데이터와 메서드를 하나로 묶고 보호하는 것
  • private: 클래스 내부에서만 접근 가능 (가장 안전)
  • public: 어디서든 접근 가능 (인터페이스)
  • protected: 상속 관계에서 사용 (다음에 배울 예정)
  • getter/setter: 안전한 데이터 접근 방법

✅ 실습 체크리스트

🚀 다음 시간 예고

다음 시간에는 멤버 함수와 this 포인터에 대해 알아볼 거예요!

  • this 포인터의 개념
  • const 멤버 함수
  • 메서드 체이닝

“캡슐화는 안전한 프로그램의 첫걸음입니다! 🔐”

Last updated on