학습
C++ 상속 (Inheritance)
C++ 상속 (Inheritance) — 중급
상속 (Inheritance)
1. 도입 (왜 배워야 하는가)
상속은 객체 지향 프로그래밍의 핵심 개념 중 하나로, 코드의 재사용성과 확장성을 향상시키는 중요한 기법입니다. 실무에서는 상속을 통해 기본 클래스의 속성과 메서드를 기반으로 새로운 클래스를 쉽게 생성할 수 있어, 개발 효율성을 극대화합니다.
예를 들어, 쇼핑몰 애플리케이션을 개발할 때 상품이라는 기본 클래스를 만들고, 이를 상속받아 전자기기, 의류, 식품 등의 클래스를 생성할 수 있습니다. 이때 기본 클래스에서 정의한 속성(예: 가격, 이름)을 자식 클래스에서 재사용할 수 있습니다. 만약 상속을 사용하지 않는다면, 중복된 코드가 발생하고 유지보수가 어려워지며, 오류 발생 가능성이 커질 수 있습니다.
2. 핵심 개념 설명
상속이란, 기존 클래스(부모 클래스)의 특성과 동작을 새로운 클래스(자식 클래스)가 물려받는 기능을 말합니다. 상속을 통해 자식 클래스는 부모 클래스의 모든 속성과 메서드를 사용할 수 있습니다.
비유
상속은 부모가 자녀에게 유전자를 물려주는 것과 비슷합니다. 부모가 가진 특성(예: 눈 색깔, 머리 모양)을 자녀가 물려받는 것처럼, 자식 클래스는 부모 클래스의 속성과 메서드를 물려받습니다.
| 용어 | 설명 |
|---|---|
| 부모 클래스 | 다른 클래스의 속성과 메서드를 상속하는 클래스 |
| 자식 클래스 | 부모 클래스를 상속받아 새로운 기능을 추가한 클래스 |
| 다중 상속 | 하나의 자식 클래스가 여러 부모 클래스를 상속받는 것 |
3. 기본 코드 예제
다음은 상속의 기본 사용법을 보여주는 간단한 코드 예제입니다.
#include <iostream>
using namespace std;
// 부모 클래스
class Animal {
public:
void speak() {
cout << "Animal makes a sound" << endl;
}
};
// 자식 클래스
class Dog : public Animal {
public:
void bark() {
cout << "Dog barks: Woof!" << endl;
}
};
int main() {
Dog myDog;
myDog.speak(); // 부모 클래스의 메서드 호출
myDog.bark(); // 자식 클래스의 메서드 호출
return 0;
}
실행 결과
Animal makes a sound
Dog barks: Woof!
코드 한 줄씩 동작 설명
#include <iostream>: 입출력 스트림을 사용하기 위해 iostream 헤더를 포함합니다.using namespace std;: std 이름공간을 사용하여 코드에서 std::를 생략할 수 있습니다.class Animal { ... };: Animal이라는 부모 클래스를 정의합니다.void speak() { ... }: Animal 클래스의 메서드로, 동물의 소리를 출력합니다.class Dog : public Animal { ... };: Dog 클래스를 정의하고, Animal 클래스를 상속받습니다.void bark() { ... }: Dog 클래스의 메서드로, 개의 울음소리를 출력합니다.int main() { ... }: 프로그램의 실행 시작점인 main 함수를 정의합니다.Dog myDog;: Dog 클래스의 객체를 생성합니다.myDog.speak();: 부모 클래스의 메서드를 호출합니다.myDog.bark();: 자식 클래스의 메서드를 호출합니다.- 상속은 코드 재사용과 유지보수를 용이하게 해준다.
- 부모 클래스의 속성과 메서드를 자식 클래스가 그대로 사용할 수 있다.
- 다중 상속은 주의가 필요하며, 필요 시에는 멤버로 포함하는 방법을 고려해야 한다.
- 다형성(Polymorphism): 상속과 함께 사용하는 중요한 개념
- 추상 클래스(Abstract Class): 일반화된 클래스를 만들기 위한 기법
- 인터페이스(Interface): 클래스 간의 계약을 정의하는 방법
4. 실전 활용 예제
예제 1: 쇼핑몰에서 장바구니 기능 구현
#include <iostream>
#include <vector>
using namespace std;
// 부모 클래스
class Item {
public:
string name;
double price;
Item(string n, double p) : name(n), price(p) {}
};
// 자식 클래스
class Book : public Item {
public:
string author;
Book(string n, double p, string a) : Item(n, p), author(a) {}
};
class Cart {
private:
vector<Item> items;
public:
void addItem(Item item) {
items.push_back(item);
}
void checkout() {
double total = 0;
for (Item* item : items) {
total += item->price;
cout << "Item: " << item->name << ", Price: " << item->price << endl;
}
cout << "Total: " << total << endl;
}
};
int main() {
Cart myCart;
Book book1("C++ Programming", 29.99, "John Doe");
myCart.addItem(&book1);
myCart.checkout();
return 0;
}
상황 설명: 쇼핑몰에서 장바구니 기능을 구현하기 위해 Item 클래스를 부모 클래스로 하고, Book 클래스를 자식 클래스로 정의하여 책 정보를 관리합니다. 장바구니에 아이템을 추가하고, 체크아웃 시 총 가격을 계산합니다.
예제 2: 게임에서 캐릭터 구현
#include <iostream>
using namespace std;
class Character {
public:
string name;
int health;
Character(string n, int h) : name(n), health(h) {}
void display() {
cout << "Character: " << name << ", Health: " << health << endl;
}
};
class Warrior : public Character {
public:
int strength;
Warrior(string n, int h, int s) : Character(n, h), strength(s) {}
void attack() {
cout << name << " attacks with strength " << strength << "!" << endl;
}
};
int main() {
Warrior warrior("Thor", 100, 50);
warrior.display();
warrior.attack();
return 0;
}
상황 설명: 게임 개발에서 캐릭터 클래스를 부모 클래스로 하고, 전사 클래스를 자식 클래스로 정의하여 전사 캐릭터의 특성과 행동을 구현합니다.
5. 흔한 실수와 주의사항
실수 1: 접근 제어자
잘못된 코드
class Base {
private:
int value;
};
class Derived : public Base {
public:
void setValue(int v) { value = v; } // 오류: value에 접근 불가
};
올바른 코드
class Base {
protected: // protected로 변경
int value;
};
실수 2: 다중 상속의 문제
잘못된 코드
class A {};
class B {};
class C : public A, public B {}; // 문제 발생 가능성
올바른 코드
class A {};
class B {};
class C : public A {
B b; // B를 C의 멤버로 포함
};