λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
ν”„λ‘œκ·Έλž˜λ° μ–Έμ–΄/C++ 기초

[C++] 16-1. 상속(Inheritance)κ³Ό 가상 ν•¨μˆ˜(Virtual Function)

by μ„œμ•„λž‘πŸ˜ 2023. 6. 23.

 

 

이번 ν¬μŠ€νŒ…λΆ€ν„°λŠ” κ²½μ–΄μ²΄λ‘œ 글을 μ“°κ² μ”λ‹ˆλ‹€. μ—¬νƒœκΉŒμ§€ ν‰μ–΄μ²΄λ‘œ ν¬μŠ€νŒ…ν–ˆλŠ”λ°, λ”±λ”±ν•œ λŠλ‚Œμ΄ λ“€μ–΄μ„œ μ§€κΈˆλΆ€ν„°λŠ” μ’€ 더 μΉœμ ˆν•˜κ²Œ μžμ„Έν•˜κ²Œ μ„€λͺ…ν•˜λ €κ³  경어체λ₯Ό μ‚¬μš©ν•˜κ² μŠ΅λ‹ˆλ‹€!

 

 

상속(Inheritance)

객체 지ν–₯의 4λŒ€ 원칙(μΊ‘μŠν™”, 좔상화, 상속, λ‹€ν˜•μ„±) 쀑 상속 그리고 λ‹€ν˜•μ„±μ„ 닀뀄보렀고 ν•©λ‹ˆλ‹€. 상속은 객체지ν–₯의 κ½ƒμ΄μž 핡심이라고도 ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 클래슀 μžμ²΄λ§ŒμœΌλ‘œλ„ 객체끼리의 관계λ₯Ό ν‘œν˜„ν•œλ‹€λ©΄, 상속을 ν†΅ν•œ λ‹€ν˜•μ„±μ€ 객체 κ°„μ˜ 관계λ₯Ό λ”μš± ν’μ„±ν•˜κ³  μ‰½κ²Œ ν‘œν˜„ν•  수 μžˆλ„λ‘ ν•˜μ£ .

 

상속을 톡해 기쑴에 μ •μ˜λœ 클래슀λ₯Ό 기반으둜 μƒˆλ‘œμš΄ 클래슀λ₯Ό μ •μ˜ν•  수 있으며, κ³΅ν†΅λœ 것을 κ³΅μœ ν•˜κ³  ν™•μž₯ κ°€λŠ₯ν•˜λ„λ‘ λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€.  μƒμ†μ€ ν΄λž˜μŠ€ κ°„μ˜ κ΄€κ³„λ₯Ό μ„€μ •ν•˜μ—¬ μ½”λ“œ μž¬μ‚¬μš©κ³Ό κ³„측적 κ΅¬μ‘°λ₯Ό κ΅¬μΆ•ν•˜λŠ” λ° μ‚¬μš©λ©λ‹ˆλ‹€. ν•œ ν΄λž˜μŠ€(νŒŒμƒ ν΄λž˜μŠ€ λ˜λŠ” ν•˜μœ„ ν΄λž˜μŠ€)κ°€ λ‹€λ₯Έ ν΄λž˜μŠ€(κΈ°λ³Έ ν΄λž˜μŠ€ λ˜λŠ” μƒμœ„ ν΄λž˜μŠ€)의 νŠΉμ„±κ³Ό λ™μž‘을 μƒμ†λ°›μ•„ ν™•μž₯ν•  μˆ˜ μžˆμŠ΅λ‹ˆλ‹€. μ΄λ₯Ό ν†΅ν•΄ μ½”λ“œμ˜ μ€‘볡을 ν”Όν•˜κ³  μœ μ§€λ³΄μˆ˜μ„±μ„ ν–₯μƒμ‹œν‚¬ μˆ˜ μžˆμŠ΅λ‹ˆλ‹€.

상속 κ΄€κ³„μ—μ„œλŠ” λΆ€λͺ¨-μžμ‹μ΄λΌλŠ” ν‘œν˜„μ„ 많이 μ‚¬μš©ν•˜λ©° κΈ°λ³Έ 클래슀(Base class)와 νŒŒμƒ(Derived class)λ‘œλ„ 많이 μ‚¬μš©ν•©λ‹ˆλ‹€.


C++μ—μ„œ μƒμ†μ„ μ •μ˜ν•˜λ €λ©΄ νŒŒμƒ ν΄λž˜μŠ€λ₯Ό μ„ μ–Έν•˜κ³  κΈ°λ³Έ ν΄λž˜μŠ€λ₯Ό μ§€μ •ν•΄μ•Ό ν•©λ‹ˆλ‹€. ν΄λž˜μŠ€ μ„ μ–Έ μ‹œ κΈ°λ³Έ ν΄λž˜μŠ€λ₯Ό μ§€μ •ν•˜κΈ° μœ„ν•΄ νŒŒμƒ ν΄λž˜μŠ€μ˜ μ„ μ–ΈλΆ€μ— μ½œλ‘ (:)을 μ‚¬μš©ν•˜λ©°, μ΄μ–΄μ„œ μ ‘κ·Ό μ§€μ •μžμ™€ ν•¨κ»˜ κΈ°λ³Έ ν΄λž˜μŠ€μ˜ μ΄λ¦„을 λͺ…μ‹œν•©λ‹ˆλ‹€. μƒμ†μ˜ μ ‘κ·Ό μ§€μ •μžλŠ” νŒŒμƒ ν΄λž˜μŠ€μ—μ„œ κΈ°λ³Έ ν΄λž˜μŠ€μ˜ λ©€λ²„에 λŒ€ν•œ μ ‘κ·Ό κΆŒν•œμ„ μ œμ–΄ν•˜λŠ” μ—­ν• μ„ ν•©λ‹ˆλ‹€.

class BaseClass {
  // κΈ°λ³Έ 클래슀 멀버듀
};

class DerivedClass : μ ‘κ·Ό_μ§€μ •μž BaseClass {
  // νŒŒμƒ 클래슀 멀버듀
};

 

C++μ—μ„œ μƒμ†μ€ λ‹€μŒκ³Ό κ°™μ€ μ„Έ κ°€μ§€ μœ ν˜•μœΌλ‘œ κ΅¬λΆ„λ©λ‹ˆλ‹€:

βœ”οΈ 곡개 상속(Public Inheritance): public μ ‘κ·Ό μ§€μ •μžλ₯Ό μ‚¬μš©ν•˜μ—¬ μƒμ†ν•©λ‹ˆλ‹€. 이 경우, κΈ°λ³Έ 클래슀의 λͺ¨λ“  곡개 λ©€λ²„λŠ” νŒŒμƒ ν΄λž˜μŠ€μ—μ„œλ„ 곡개 λ©€λ²„λ‘œ μƒμ†λ©λ‹ˆλ‹€.
βœ”οΈ λ³΄ν˜Έ μƒμ†(Protected Inheritance): protected μ ‘κ·Ό μ§€μ •μžλ₯Ό μ‚¬μš©ν•˜μ—¬ μƒμ†ν•©λ‹ˆλ‹€. μ΄ κ²½μš°, κΈ°λ³Έ ν΄λž˜μŠ€μ˜ λͺ¨λ“  κ³΅κ°œ λ° λ³΄ν˜Έ λ©€λ²„λŠ” νŒŒμƒ ν΄λž˜μŠ€μ—μ„œ λ³΄ν˜Έ λ©€λ²„λ‘œ μƒμ†λ©λ‹ˆλ‹€.
βœ”οΈ λΉ„κ³΅κ°œ μƒμ†(Private Inheritance): private μ ‘κ·Ό μ§€μ •μžλ₯Ό μ‚¬μš©ν•˜μ—¬ μƒμ†ν•©λ‹ˆλ‹€. μ΄ κ²½μš°, κΈ°λ³Έ ν΄λž˜μŠ€μ˜ λͺ¨λ“  λ©€λ²„λŠ” νŒŒμƒ ν΄λž˜μŠ€μ—μ„œ λΉ„κ³΅κ°œ λ©€λ²„λ‘œ μƒμ†λ©λ‹ˆλ‹€.


νŒŒμƒ ν΄λž˜μŠ€λŠ” κΈ°λ³Έ ν΄λž˜μŠ€μ—μ„œ μƒμ†λ°›μ€ λ©€λ²„λ₯Ό μ‚¬μš©ν•  μˆ˜ μžˆμœΌλ©°, ν•„μš”μ— λ”°λΌ μƒˆλ‘œμš΄ λ©€λ²„λ₯Ό μΆ”κ°€ν•˜κ±°λ‚˜ κΈ°μ‘΄ λ©€λ²„λ₯Ό μž¬μ •μ˜(μ˜€λ²„λΌμ΄λ”©)ν•  μˆ˜ μžˆμŠ΅λ‹ˆλ‹€. μƒμ†λ°›μ€ λ©€λ²„에 μ ‘κ·Όν•˜κΈ° μœ„ν•΄ . μ—°μ‚°μžλ₯Ό μ‚¬μš©ν•  μˆ˜ μžˆμŠ΅λ‹ˆλ‹€. λ˜ν•œ, νŒŒμƒ ν΄λž˜μŠ€μ˜ μƒμ„±μžμ—μ„œ κΈ°λ³Έ ν΄λž˜μŠ€μ˜ μƒμ„±μžλ₯Ό ν˜ΈμΆœν•˜μ—¬ μ΄ˆκΈ°ν™”ν•˜λŠ” κ²ƒμ΄ μΌλ°˜μ μž…λ‹ˆλ‹€.

#include <iostream>

// κΈ°λ³Έ 클래슀: 동물
class Animal {
public:
    void eat() {
        std::cout << "동물이 λ¨Ήκ³  μžˆμŠ΅λ‹ˆλ‹€." << std::endl;
    }
};

// νŒŒμƒ 클래슀: 고양이
class Cat : public Animal {
public:
    void meow() {
        std::cout << "고양이가 μ•Όμ˜Ή μ†Œλ¦¬λ₯Ό λ‚΄κ³  μžˆμŠ΅λ‹ˆλ‹€." << std::endl;
    }
};

int main() {
    // νŒŒμƒ 클래슀의 객체 생성
    Cat cat;

    // 상속받은 κΈ°λ³Έ 클래슀의 멀버 μ‚¬μš©
    cat.eat();

    // νŒŒμƒ 클래슀의 멀버 μ‚¬μš©
    cat.meow();

    return 0;
}

/* μ‹€ν–‰κ²°κ³Ό
동물이 λ¨Ήκ³  μžˆμŠ΅λ‹ˆλ‹€.
고양이가 μ•Όμ˜Ή μ†Œλ¦¬λ₯Ό λ‚΄κ³  μžˆμŠ΅λ‹ˆλ‹€.
*/

 

 

닀쀑 μƒμ†(Multiple Inheritance)이라고 ν•˜λŠ” κ°œλ…λ„ μžˆμœΌλ©°, C++μ—μ„œλŠ” ν΄λž˜μŠ€κ°€ λ‘ κ°œ μ΄μƒμ˜ ν΄λž˜μŠ€λ‘œλΆ€ν„° λ™μ‹œμ— μƒμ†λ°›μ„ μˆ˜ μžˆμŠ΅λ‹ˆλ‹€. μ΄λ₯Ό ν†΅ν•΄ λ‹€λ₯Έ ν΄λž˜μŠ€μ˜ νŠΉμ„±κ³Ό λ™μž‘을 μ‘°ν•©ν•˜μ—¬ μƒˆλ‘œμš΄ ν΄λž˜μŠ€λ₯Ό μ •μ˜ν•  μˆ˜ μžˆμŠ΅λ‹ˆλ‹€. λ‹€μ€‘ μƒμ†μ€ μœ μš©ν•˜μ§€λ§Œ μ½”λ“œμ˜ λ³΅μž‘성을 μ¦κ°€μ‹œν‚¬ μˆ˜ μžˆμœΌλ―€λ‘œ μ‹ μ€‘ν•˜κ²Œ μ‚¬μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€.

 

 

 

가상 ν•¨μˆ˜(Virtual Function)와 μ˜€λ²„λΌμ΄λ”©(Overriding)

가상 ν•¨μˆ˜(Virtual Function)λŠ” κΈ°λ³Έ ν΄λž˜μŠ€μ™€ νŒŒμƒ ν΄λž˜μŠ€ μ‚¬μ΄μ—μ„œ λ™μ  λ°”인딩을 μ§€μ›ν•˜κΈ° μœ„ν•΄ μ‚¬μš©λ˜λŠ” ν•¨μˆ˜μž…λ‹ˆλ‹€. λ™μ  λ°”인딩은 μ‹€ν–‰ μ‹œκ°„에 μ μ ˆν•œ ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜κΈ° μœ„ν•΄ κ°€μƒ ν•¨μˆ˜ ν…Œμ΄λΈ”(virtual function table)을 μ‚¬μš©ν•˜λŠ” λ©”μ»€λ‹ˆμ¦˜μž…λ‹ˆλ‹€. κ°€μƒ ν•¨μˆ˜λŠ” κΈ°λ³Έ ν΄λž˜μŠ€μ—μ„œ μ •μ˜λ˜λ©°, νŒŒμƒ ν΄λž˜μŠ€μ—μ„œ ν•„μš”μ— λ”°λΌ μž¬μ •μ˜(μ˜€λ²„λΌμ΄λ”©)될 μˆ˜ μžˆμŠ΅λ‹ˆλ‹€.

가상 ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜κΈ° μœ„ν•΄μ„œλŠ” λ‹€μŒκ³Ό κ°™μ€ κ·œμΉ™μ„ λ”°λΌμ•Ό ν•©λ‹ˆλ‹€:

1. κΈ°λ³Έ ν΄λž˜μŠ€μ—μ„œ 가상 ν•¨μˆ˜λ₯Ό μ„ μ–Έν•  λ•Œ virtual ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.
2. νŒŒμƒ ν΄λž˜μŠ€μ—μ„œ λ™μΌν•œ 이름과 μ‹œκ·Έλ‹ˆμ²˜λ₯Ό 가진 ν•¨μˆ˜λ₯Ό override ν‚€μ›Œλ“œμ™€ ν•¨κ»˜ μž¬μ •μ˜ν•©λ‹ˆλ‹€.
3. 가상 ν•¨μˆ˜λŠ” 일반적으둜 κΈ°λ³Έ 클래슀의 멀버 ν•¨μˆ˜λ‘œ μ„ μ–Έλ©λ‹ˆλ‹€. κΈ°λ³Έ ν΄λž˜μŠ€μ—μ„œ 가상 ν•¨μˆ˜λ₯Ό 순수 가상 ν•¨μˆ˜λ‘œ μ„ μ–Έν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.

 

#include <iostream>

// κΈ°λ³Έ 클래슀: 동물
class Animal {
protected:
    int age = 1;
    int numOfLegs = 4;

public:
    void walk() {
        std::cout << "동물이 " << numOfLegs << "개의 발둜 κ±·κ³  μžˆμŠ΅λ‹ˆλ‹€." << std::endl;
    }

    virtual void sound() {
        std::cout << "동물이 μ†Œλ¦¬λ₯Ό λ‚΄κ³  μžˆμŠ΅λ‹ˆλ‹€." << std::endl;
    }
};

// νŒŒμƒ 클래슀: 고양이
class Cat : public Animal {
public:
    virtual void sound() override final {
        std::cout << "고양이가 μ•Όμ˜Ή μ†Œλ¦¬λ₯Ό λ‚΄κ³  μžˆμŠ΅λ‹ˆλ‹€." << std::endl;
    }
    
    void jump() {
        std::cout << "고양이가 점프 ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€." << std::endl;
    }
    
    void setAge(int _age) {
        age = _age;
    }

    void setLegs(int _legs) {
        numOfLegs = _legs;
    }
};

int main() {
    // νŒŒμƒ 클래슀의 객체 생성
    Cat cat;

    // κΈ°λ³Έ 클래슀의 멀버 λ³€μˆ˜ μ ‘κ·Ό
    cat.setAge(10);
    cat.setLegs(4);

    // νŒŒμƒ 클래슀의 멀버 ν•¨μˆ˜ 호좜
    cat.jump();

    // μ˜€λ²„λΌμ΄λ”©λœ 멀버 ν•¨μˆ˜ 호좜
    cat.sound();

    // κΈ°λ³Έ 클래슀의 멀버 ν•¨μˆ˜ 호좜
    cat.Animal::sound();

    return 0;
}

/* 좜λ ₯ κ²°κ³Ό
고양이가 점프 ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.       
동물이 4개의 발둜 κ±·κ³  μžˆμŠ΅λ‹ˆλ‹€.   
고양이가 μ•Όμ˜Ή μ†Œλ¦¬λ₯Ό λ‚΄κ³  μžˆμŠ΅λ‹ˆλ‹€.
동물이 μ†Œλ¦¬λ₯Ό λ‚΄κ³  μžˆμŠ΅λ‹ˆλ‹€.
*/

protectedλŠ” 상속 κ΄€κ³„μ—μ„œ μžμ‹μ΄ λΆ€λͺ¨μ˜ 멀버에 μ ‘κ·Ό κ°€λŠ₯ν•˜λ„λ‘ ν•©λ‹ˆλ‹€. μœ„ μ˜ˆμ œμ—μ„œλ„ μžμ‹ 클래슀인 Cat이 λΆ€λͺ¨ 클래슀인 Animal 클래슀의 age와 numOfLegs에 μ ‘κ·Ό κ°€λŠ₯ν•©λ‹ˆλ‹€. λ¬Όλ‘  public은 μ•„λ‹ˆκΈ° λ•Œλ¬Έμ— main ν•¨μˆ˜μ—μ„œ cat.age = 4;λŠ” λΆˆκ°€λŠ₯ν•©λ‹ˆλ‹€.λΆ€λͺ¨λ„, μžμ‹λ„ μ•„λ‹Œ μ™ΈλΆ€λ‹ˆκΉŒμš”.

그리고 λ©”μ†Œλ“œ μ˜€λ²„λΌμ΄λ”©(Method Overriding)은 λΆ€λͺ¨ 클래슀의 μ •μ˜λœ ν•¨μˆ˜λ₯Ό μžμ‹ ν΄λž˜μŠ€μ—μ„œ μž¬μ •μ˜ ν•˜λŠ” 것을 λ§ν•©λ‹ˆλ‹€. λ”°λΌμ„œ ν•¨μˆ˜μ˜ μ„ μ–Έ ꡬ쑰λ₯Ό κ·ΈλŒ€λ‘œ 따라가야 ν•©λ‹ˆλ‹€. 그리고 μžμ‹ ν΄λž˜μŠ€μ—μ„œλŠ” 이 ν•¨μˆ˜κ°€ μž¬μ •μ˜ λ˜μ—ˆλ‹€λŠ” 것을 ν‘œκΈ°ν•˜κΈ° μœ„ν•΄ ν•¨μˆ˜ μ˜†μ— overrideλ₯Ό λΆ™μž…λ‹ˆλ‹€. 그리고 μ—¬λŸ¬ λ‹¨κ³„μ˜ 상속이 있고, μž¬μ •μ˜λ₯Ό μžμ‹μ˜ μžμ‹μ—μ„œλ„ ν•  수 있기 λ•Œλ¬Έμ— μ—¬κΈ°κ°€ λ§ˆμ§€λ§‰ μž¬μ •μ˜λΌλŠ” 것을 μ˜λ―Έν•˜λŠ” final도 λΆ™μ˜€μŠ΅λ‹ˆλ‹€.

 

λ‹€μŒμ€ 순수 가상 ν•¨μˆ˜μ™€ 좔상 클래슀, 그리고 λ‹€ν˜•μ„±μ— λŒ€ν•΄ μ•Œμ•„λ³΄κ² μŠ΅λ‹ˆλ‹€!

 

λŒ“κΈ€