언리얼 엔진/개념 정리

개념 정리 - C++ (상속, 다형성)

journey46110 2026. 7. 17. 19:17

I. 상속 (Inheritance)

1) 상속의 필요성

비슷한 클래스가 여러 개 있을 때 공통 코드를 재사용하기 위해 사용함

 

예시 - 자동차, 자전거, 트럭은 색깔과 속도라는 공통 부분이 있음

class Bicycle
{
    string color;
    int speed;
};

class Truck
{
    string color;
    int speed;
};

각각 구현하면 중복이 생김

 

        Vehicle
      /         \
 Bicycle       Truck

그래서 공통 부분을 기본 클래스(부모 클래스)로 따로 뺌

 

 

2) 상속 문법

class Vehicle
{
};

class Bicycle : public Vehicle
{
};

Bicycle은 Vehicle을 상속받음

Bicycle의 기능과 Vehicle의 기능을 모두 가짐

 

 

3) Is-A 관계

상속을 사용할 수 있는 가장 쉬운 기준

 

예시

Bicycle은 Vehicle이다. (O)

Truck은 Vehicle이다. (O)

-> 이런 경우 상속에 해당함

 

잘못된 예시

Engine은 Vehicle이다. (X)
Vehicle은 Engine을 가진다. (O)
-> 이런 경우 포함(Composition)에 해당함

 

 

4) 부모 생성자 호출

자식 클래스(파생 클래스) 생성 시 부모 클래스가 먼저 생성되어야 함

class Vehicle
{
public:
    Vehicle(string color, int speed)
    {
    }
};

class Bicycle : public Vehicle
{
public:
    Bicycle(string color, int speed)
        : Vehicle(color, speed)
    {
    }
};

순서: Vehicle 생성 -> Bicycle 생성

 

 

5) 멤버 초기화 리스트

생성자보다 먼저 실행됨

Person(string n)
    : name(n)
{
}

기존에 쓰던 name=n; 보다 효율적

 

 

6) 상속 활용 예시

#include <iostream>
#include <string>

using namespace std;

// 부모 클래스
class Vehicle {
protected:
    string color;
    int speed;

public:
    Vehicle(string c, int s) : color(c), speed(s) {}

    void move() {
        cout << color << " vehicle is moving at "
             << speed << " km/h." << endl;
    }

    void stop() {
        cout << "The vehicle has stopped." << endl;
    }

    string getColor() {
        return color;
    }
};

// 자전거
class Bicycle : public Vehicle {
private:
    bool hasBasket;

public:
    Bicycle(string c, int s, bool basket)
        : Vehicle(c, s), hasBasket(basket) {}

    void ringBell() {
        cout << "Ring Ring!" << endl;
    }

    void showBasket() {
        if (hasBasket)
            cout << "This bicycle has a basket." << endl;
        else
            cout << "This bicycle doesn't have a basket." << endl;
    }
};

// 자동차
class Car : public Vehicle {
private:
    int doorCount;

public:
    Car(string c, int s, int door)
        : Vehicle(c, s), doorCount(door) {}

    void openDoor() {
        cout << doorCount << " doors are available." << endl;
    }
};

// 비행기
class Airplane : public Vehicle {
private:
    int altitude;

public:
    Airplane(string c, int s, int alt)
        : Vehicle(c, s), altitude(alt) {}

    void fly() {
        cout << "Flying at " << altitude << " meters." << endl;
    }
};

int main() {
    Bicycle bicycle("Yellow", 20, true);
    Car car("Black", 100, 4);
    Airplane airplane("White", 800, 10000);

    bicycle.move();
    bicycle.ringBell();
    bicycle.showBasket();

    cout << endl;

    car.move();
    car.openDoor();

    cout << endl;

    airplane.move();
    airplane.fly();

    cout << endl;

    bicycle.stop();
    car.stop();
    airplane.stop();

    return 0;
}

 

 

II. 다형성 (Polymorphism)

1) 다형성의 필요성

① 다형성을 적용하지 않은 코드

class Lion
{
public:
	void bark() { cout << "Lion 아아아아아아" << endl; }
};

class Wolf
{
public:
	void bark() { cout << "Wolf 아우우우우우우" << endl; }
};

void print(Lion lion)
{
	lion.bark();
}

void print(Wolf wolf)
{
	wolf.bark();
}

int main()
{
	Lion lion();
	Wolf wolf();

	print(lion);
	print(wolf);

	return 0;
}

class가 더 늘어나면 print 함수도 새로 더 만들어줘야 함 -> 비효율적임

 

② 다형성을 적용한 코드

class Animal
{
public:
	Animal() {}
	virtual void bark() {};
};

class Lion : public Animal
{
public:
	void bark() { cout << "Lion 아아아아아아" << endl; }
};

class Wolf : public Animal
{
public:
	void bark() { cout << "Wolf 아우우우우우우" << endl; }
};

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

void print(Animal* animal)
{
	animal->bark();
}

int main()
{
	Lion lion();
	Wolf wolf();
	Dog dog();

	print(&lion);
	print(&wolf);
	print(&dog);

	return 0;
}

부모 클래스를 만들어서 자식 클래스를 모두 다룰 수 있음

 

 

2) 가상 함수 (Virtual Function)

다형성에서 가장 중요한 키워드

virtual void bark()
{
}

 

① virtual을 사용하는 경우

동적 바인딩: 실행 중에 실체 객체가 무엇인지 확인 후 해당 함수 호출하는 기능

Animal*
↓
동적 바인딩
(실제 객체 확인
↓
Dog인가?
↓
Dog::bark() 호출)

Dog::bark()가 호출됨

 

② virtual을 사용하지 않는 경우

Animal* animal;
Dog dog;

animal = &dog;

animal->bark();
↓
Animal::bark() 호출

dog의 주소를 가리켜도 Animal::bark()가 호출됨

 

 

3) 재정의 (Override)

부모의 함수를 자식에서 다시 구현하는 것

class Animal
{
public:
    virtual void sound()
    {
        cout << "Animal";
    }
};

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

override는 부모 함수를 재정의하는 것이 맞는지 컴파일러가 확인해주는 역할

 

 

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

기본 클래스가 함수를 아예 구현하지 않음

virtual void sound() = 0;

인터페이스만 제공, 구현은 자식 클래스에서 함

 

일반 가상 함수는 구현을 하고, 재정의는 자식 클래스에서 여부를 선택함

순수 가상 함수는 구현을 하지 않고, 재정의를 반드시 해줘야 함

 

 

5) 추상 클래스 (Abstract Class)

순수 가상 함수가 하나라도 있으면 추상 클래스임

class Animal
{
public:
    virtual void sound() = 0;
};

 

Animal animal; (불가능)

Animal *animal;
animal = &dog; (가능)

 

Animal은 인터페이스만 있을 뿐 이제 더 이상 인스턴스화가 될 수 없음

 

 

6) 추상 클래스 활용 예시

#include <iostream>
using namespace std;

// 기본 클래스 (추상 클래스)
class Skill {
public:
    virtual void use() = 0;
};

// 파생 클래스 : Fireball
class Fireball : public Skill {
public:
    void use() override {
        cout << "Fireball! Deal 100 fire damage." << endl;
    }
};

// 파생 클래스 : Heal
class Heal : public Skill {
public:
    void use() override {
        cout << "Heal! Recover 80 HP." << endl;
    }
};

// 파생 클래스 : Dash
class Dash : public Skill {
public:
    void use() override {
        cout << "Dash! Move quickly forward." << endl;
    }
};

int main() {
    Skill* skill;

    Fireball fireball;
    Heal heal;
    Dash dash;

    skill = &fireball;
    skill->use();

    skill = &heal;
    skill->use();

    skill = &dash;
    skill->use();

    return 0;
}