c++

C++ 객체 지향 프로그래밍: 상속과 다형성

난개발자 2025. 2. 1. 18:17
728x90

이전 포스팅에서는 **C++ 객체 지향 프로그래밍(OOP)**의 기본 개념과 클래스, 객체에 대해 알아보았습니다. 이번 글에서는 **상속(Inheritance)**과 **다형성(Polymorphism)**이라는 두 가지 핵심 OOP 개념을 소개하고, C++에서 이를 어떻게 구현하는지 살펴보겠습니다.


1. 상속(Inheritance)란?

상속은 기존 클래스의 속성과 메서드를 새로운 클래스에 물려주는 기능입니다. 이를 통해 코드의 재사용성을 높이고, 유지보수를 쉽게 할 수 있습니다.

(1) 기본 상속 구조

  • 부모 클래스(기초 클래스, Base Class): 기존 클래스
  • 자식 클래스(파생 클래스, Derived Class): 부모 클래스로부터 상속받은 새로운 클래스
#include <iostream>
using namespace std;

// 부모 클래스
class Animal {
public:
    void eat() {
        cout << "먹고 있습니다." << endl;
    }
};

// 자식 클래스 (Animal을 상속받음)
class Dog : public Animal {
public:
    void bark() {
        cout << "멍멍!" << endl;
    }
};

int main() {
    Dog myDog;
    myDog.eat();  // 부모 클래스의 메서드 사용
    myDog.bark(); // 자식 클래스의 메서드 사용
    return 0;
}

(2) 출력 결과:

먹고 있습니다.
멍멍!

(3) 상속의 종류

  1. 공개 상속(public inheritance): 부모 클래스의 public 멤버가 자식 클래스에서도 public으로 유지됩니다.
  2. 보호 상속(protected inheritance): 부모 클래스의 public 멤버가 자식 클래스에서 protected로 변환됩니다.
  3. 비공개 상속(private inheritance): 부모 클래스의 public 멤버가 자식 클래스에서 private으로 변환됩니다.

2. 오버라이딩(Overriding)

상속받은 메서드를 **자식 클래스에서 재정의(Override)**할 수 있습니다.

class Animal {
public:
    void sound() {
        cout << "동물이 소리를 냅니다." << endl;
    }
};

class Dog : public Animal {
public:
    void sound() {  // 부모 클래스의 메서드를 재정의
        cout << "개가 멍멍 짖습니다." << endl;
    }
};

int main() {
    Dog myDog;
    myDog.sound();  // 자식 클래스의 sound() 호출
    return 0;
}

출력 결과:

개가 멍멍 짖습니다.

3. 다형성(Polymorphism)이란?

다형성은 하나의 인터페이스가 여러 형태로 동작할 수 있게 하는 개념입니다. C++에서 다형성을 구현하려면 **가상 함수(virtual function)**와 포인터 또는 **참조(reference)**를 활용합니다.

(1) 가상 함수(Virtual Function)

가상 함수는 부모 클래스에서 선언하고, 자식 클래스에서 재정의할 수 있습니다.

class Animal {
public:
    virtual void sound() {  // 가상 함수
        cout << "동물이 소리를 냅니다." << endl;
    }
};

class Dog : public Animal {
public:
    void sound() override {  // 가상 함수 재정의
        cout << "개가 멍멍 짖습니다." << endl;
    }
};

class Cat : public Animal {
public:
    void sound() override {
        cout << "고양이가 야옹거립니다." << endl;
    }
};

int main() {
    Animal* animalPtr;
    Dog dog;
    Cat cat;

    animalPtr = &dog;
    animalPtr->sound();  // 개가 멍멍 짖습니다.

    animalPtr = &cat;
    animalPtr->sound();  // 고양이가 야옹거립니다.

    return 0;
}

(2) 출력 결과:

개가 멍멍 짖습니다.
고양이가 야옹거립니다.
  • virtual 키워드가 없다면 부모 클래스의 sound() 메서드가 호출됩니다.
  • override 키워드는 가상 함수를 재정의하고 있다는 것을 명시합니다.

4. 추상 클래스(Abstract Class)와 순수 가상 함수

(1) 추상 클래스란?

추상 클래스는 **순수 가상 함수(pure virtual function)**를 포함한 클래스입니다. 추상 클래스는 객체로 생성할 수 없으며, 상속받은 클래스에서 반드시 해당 함수를 구현해야 합니다.

(2) 순수 가상 함수 정의

class Animal {
public:
    virtual void sound() = 0;  // 순수 가상 함수
};

class Dog : public Animal {
public:
    void sound() override {
        cout << "개가 멍멍 짖습니다." << endl;
    }
};

int main() {
    Dog myDog;
    myDog.sound();
    return 0;
}

(3) 출력 결과:

개가 멍멍 짖습니다.
  • virtual void sound() = 0;순수 가상 함수를 의미합니다.
  • 추상 클래스인 Animal은 객체로 생성할 수 없습니다.

5. 다형성의 실전 예제: 동물 소리 내기 프로그램

#include <vector>

class Animal {
public:
    virtual void sound() = 0;  // 순수 가상 함수
};

class Dog : public Animal {
public:
    void sound() override {
        cout << "멍멍!" << endl;
    }
};

class Cat : public Animal {
public:
    void sound() override {
        cout << "야옹!" << endl;
    }
};

int main() {
    vector<Animal*> animals;  // Animal 포인터의 벡터

    animals.push_back(new Dog());
    animals.push_back(new Cat());

    for (Animal* animal : animals) {
        animal->sound();  // 각 동물의 소리 출력
    }

    // 메모리 해제
    for (Animal* animal : animals) {
        delete animal;
    }

    return 0;
}

출력 결과:

멍멍!
야옹!

이렇게 다형성을 이용하면 같은 인터페이스(sound())로 다양한 객체(Dog, Cat)의 동작을 쉽게 관리할 수 있습니다.

728x90