Skip to Content
💻 코리아IT아카데미 신촌 - 프로그래밍 학습 자료
C++ 프로그래밍Unit 12: 상속과 다형성Topic 3: 추상 클래스와 인터페이스

Topic 3: 추상 클래스와 인터페이스 📐

🎯 학습 목표

  • 순수 가상 함수의 개념을 이해할 수 있다
  • 추상 클래스를 설계하고 활용할 수 있다
  • 인터페이스 패턴을 구현할 수 있다
  • 추상화의 중요성을 설명할 수 있다

📐 설계도로 이해하는 추상 클래스

추상 클래스는 마치 건축 설계도와 같습니다!

집 설계도의 특징 🏠

  • 📝 설계도만으로는 살 수 없음: 실제 집을 지어야 함
  • 🏗️ 기본 구조 제공: 방, 화장실, 주방의 위치
  • 🎨 세부사항은 자유: 인테리어, 색상은 각자 선택
// 추상 클래스 = 설계도 class HouseBlueprint { virtual void buildRoof() = 0; // 지붕 (구체적 방법은 미정) virtual void buildWalls() = 0; // 벽 (구체적 방법은 미정) virtual void buildDoor() = 0; // 문 (구체적 방법은 미정) }; // 실제 집 = 구체 클래스 class MyHouse : public HouseBlueprint { void buildRoof() { /* 기와 지붕 */ } void buildWalls() { /* 벽돌 벽 */ } void buildDoor() { /* 나무 문 */ } };

🌟 순수 가상 함수 (Pure Virtual Function)

순수 가상 함수란?

구현이 없는 가상 함수 = 자식 클래스가 반드시 구현해야 함!

class AbstractClass { public: // 순수 가상 함수 선언 virtual void pureVirtualFunction() = 0; // = 0이 핵심! // 일반 가상 함수 (구현 있음) virtual void normalVirtualFunction() { cout << "기본 구현" << endl; } // 일반 함수 void normalFunction() { cout << "일반 함수" << endl; } };

🎮 실습: 게임 아이템 시스템

#include <iostream> #include <vector> #include <string> using namespace std; // 추상 클래스 - 게임 아이템 class Item { protected: string name; int price; string rarity; // 일반, 희귀, 전설 public: Item(string n, int p, string r) : name(n), price(p), rarity(r) {} // 순수 가상 함수들 - 자식이 반드시 구현! virtual void use() = 0; virtual string getDescription() = 0; virtual string getType() = 0; // 일반 가상 함수 - 기본 구현 제공 virtual void showInfo() { cout << "\n=== " << name << " ===" << endl; cout << "종류: " << getType() << endl; cout << "등급: " << rarity << endl; cout << "가격: " << price << " 골드" << endl; cout << "설명: " << getDescription() << endl; } // 일반 함수 string getName() const { return name; } int getPrice() const { return price; } }; // 무기 클래스 class Weapon : public Item { private: int damage; public: Weapon(string n, int p, string r, int dmg) : Item(n, p, r), damage(dmg) {} void use() override { cout << "⚔️ " << name << "을(를) 장착했습니다!" << endl; cout << " 공격력 +" << damage << endl; } string getDescription() override { return "공격력을 " + to_string(damage) + " 증가시키는 무기"; } string getType() override { return "무기"; } }; // 포션 클래스 class Potion : public Item { private: int healAmount; public: Potion(string n, int p, string r, int heal) : Item(n, p, r), healAmount(heal) {} void use() override { cout << "🧪 " << name << "을(를) 마셨습니다!" << endl; cout << " HP +" << healAmount << " 회복!" << endl; } string getDescription() override { return "HP를 " + to_string(healAmount) + " 회복시키는 포션"; } string getType() override { return "포션"; } }; // 방어구 클래스 class Armor : public Item { private: int defense; public: Armor(string n, int p, string r, int def) : Item(n, p, r), defense(def) {} void use() override { cout << "🛡️ " << name << "을(를) 장착했습니다!" << endl; cout << " 방어력 +" << defense << endl; } string getDescription() override { return "방어력을 " + to_string(defense) + " 증가시키는 방어구"; } string getType() override { return "방어구"; } }; // 인벤토리 시스템 class Inventory { private: vector<Item*> items; int gold; public: Inventory(int initialGold = 1000) : gold(initialGold) { cout << "🎒 인벤토리 생성 (보유 골드: " << gold << ")" << endl; } ~Inventory() { for (Item* item : items) { delete item; } } void addItem(Item* item) { items.push_back(item); cout << "✅ " << item->getName() << " 획득!" << endl; } void showAllItems() { cout << "\n=== 🎒 인벤토리 ===" << endl; cout << "보유 골드: " << gold << endl; cout << "아이템 개수: " << items.size() << endl; for (size_t i = 0; i < items.size(); i++) { cout << "\n[" << i+1 << "]"; items[i]->showInfo(); } } void useItem(int index) { if (index > 0 && index <= items.size()) { items[index-1]->use(); } else { cout << "❌ 잘못된 아이템 번호입니다!" << endl; } } }; int main() { cout << "=== RPG 아이템 시스템 ===" << endl; Inventory myInventory(5000); // 다양한 아이템 추가 myInventory.addItem(new Weapon("전설의 검", 1000, "전설", 50)); myInventory.addItem(new Potion("체력 포션", 50, "일반", 30)); myInventory.addItem(new Armor("드래곤 갑옷", 2000, "전설", 40)); myInventory.addItem(new Weapon("철검", 100, "일반", 10)); myInventory.addItem(new Potion("대형 체력 포션", 200, "희귀", 100)); // 인벤토리 표시 myInventory.showAllItems(); // 아이템 사용 cout << "\n=== 아이템 사용 ===" << endl; myInventory.useItem(1); // 전설의 검 myInventory.useItem(2); // 체력 포션 myInventory.useItem(3); // 드래곤 갑옷 return 0; }

🔌 인터페이스 패턴

C++에는 인터페이스 키워드가 없지만, 순수 가상 함수만 있는 클래스로 구현합니다!

#include <iostream> #include <vector> using namespace std; // 인터페이스 1 - 공격 가능 class IAttackable { public: virtual void attack() = 0; virtual int getDamage() = 0; virtual ~IAttackable() {} }; // 인터페이스 2 - 방어 가능 class IDefendable { public: virtual void defend() = 0; virtual int getDefense() = 0; virtual ~IDefendable() {} }; // 인터페이스 3 - 이동 가능 class IMovable { public: virtual void move(int x, int y) = 0; virtual int getSpeed() = 0; virtual ~IMovable() {} }; // 전사 - 공격, 방어, 이동 모두 가능 class Warrior : public IAttackable, public IDefendable, public IMovable { private: string name; int damage; int defense; int speed; int x, y; public: Warrior(string n) : name(n), damage(20), defense(15), speed(5), x(0), y(0) { cout << "⚔️ 전사 " << name << " 생성" << endl; } // IAttackable 구현 void attack() override { cout << name << "의 검 공격! 💥" << endl; } int getDamage() override { return damage; } // IDefendable 구현 void defend() override { cout << name << "이(가) 방패로 막습니다! 🛡️" << endl; } int getDefense() override { return defense; } // IMovable 구현 void move(int newX, int newY) override { x = newX; y = newY; cout << name << "이(가) (" << x << ", " << y << ")로 이동 🏃" << endl; } int getSpeed() override { return speed; } }; // 탑 - 공격과 방어만 가능 (이동 불가) class Tower : public IAttackable, public IDefendable { private: string name; int damage; int defense; public: Tower(string n) : name(n), damage(30), defense(50) { cout << "🏰 방어탑 " << name << " 건설" << endl; } // IAttackable 구현 void attack() override { cout << name << "의 포탄 발사! 💣" << endl; } int getDamage() override { return damage; } // IDefendable 구현 void defend() override { cout << name << "의 방어막 작동! 🔰" << endl; } int getDefense() override { return defense; } }; // 정찰병 - 이동만 가능 (공격, 방어 불가) class Scout : public IMovable { private: string name; int speed; int x, y; public: Scout(string n) : name(n), speed(15), x(0), y(0) { cout << "🏃 정찰병 " << name << " 생성" << endl; } void move(int newX, int newY) override { x = newX; y = newY; cout << name << "이(가) 빠르게 (" << x << ", " << y << ")로 이동! 💨" << endl; } int getSpeed() override { return speed; } }; // 전투 시스템 void performBattle(IAttackable* attacker, IDefendable* defender) { cout << "\n⚔️ 전투 시작!" << endl; attacker->attack(); cout << "데미지: " << attacker->getDamage() << endl; defender->defend(); cout << "방어력: " << defender->getDefense() << endl; int actualDamage = attacker->getDamage() - defender->getDefense(); if (actualDamage > 0) { cout << "💥 " << actualDamage << " 데미지!" << endl; } else { cout << "🛡️ 공격이 막혔습니다!" << endl; } } int main() { cout << "=== 인터페이스 패턴 시스템 ===" << endl; // 다양한 유닛 생성 Warrior warrior("아서"); Tower tower("수호탑"); Scout scout("정찰병1"); cout << "\n=== 유닛 동작 테스트 ===" << endl; // 이동 가능한 유닛들 IMovable* movables[] = {&warrior, &scout}; for (IMovable* unit : movables) { unit->move(10, 20); } // 전투 테스트 performBattle(&warrior, &tower); performBattle(&tower, &warrior); return 0; }

📊 추상 클래스 vs 인터페이스

특징추상 클래스인터페이스
목적공통 기능 제공계약/규약 정의
구현일부 구현 가능구현 없음 (순수 가상만)
멤버 변수가능불가능 (또는 static만)
다중 상속제한적자유롭게 가능
사용 시기is-a 관계can-do 관계

🏗️ 플러그인 시스템 예제

// 플러그인 인터페이스 class IPlugin { public: virtual void initialize() = 0; virtual void execute() = 0; virtual void shutdown() = 0; virtual string getName() = 0; virtual string getVersion() = 0; virtual ~IPlugin() {} }; // 구체적인 플러그인 구현 class AudioPlugin : public IPlugin { public: void initialize() override { cout << "🔊 오디오 플러그인 초기화" << endl; } void execute() override { cout << "🎵 오디오 처리 중..." << endl; } void shutdown() override { cout << "🔇 오디오 플러그인 종료" << endl; } string getName() override { return "AudioPlugin"; } string getVersion() override { return "1.0.0"; } }; // 플러그인 매니저 class PluginManager { private: vector<IPlugin*> plugins; public: void registerPlugin(IPlugin* plugin) { plugins.push_back(plugin); cout << "✅ " << plugin->getName() << " v" << plugin->getVersion() << " 등록 완료" << endl; } void initializeAll() { for (IPlugin* plugin : plugins) { plugin->initialize(); } } void executeAll() { for (IPlugin* plugin : plugins) { plugin->execute(); } } void shutdownAll() { for (IPlugin* plugin : plugins) { plugin->shutdown(); } } };

💡 핵심 정리

  • 순수 가상 함수: = 0으로 선언, 구현 없음
  • 추상 클래스: 순수 가상 함수를 하나 이상 가진 클래스
  • 인터페이스: 순수 가상 함수만 있는 클래스 (관례)
  • 객체 생성 불가: 추상 클래스는 직접 객체 생성 불가
  • 상속 강제: 자식 클래스가 반드시 구현해야 함

✅ 실습 체크리스트

🚀 다음 시간 예고

다음 시간에는 다중 상속과 가상 상속에 대해 알아볼 거예요!

  • 다중 상속의 문제점
  • 다이아몬드 문제
  • 가상 상속으로 해결

“추상화로 더 유연한 설계를 만드세요! 📐”

Last updated on