λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
C++ 기초

[C++] 16-3. 상속(Inheritance)κ΄€κ³„μ˜ μΈμŠ€ν„΄μŠ€ 생성, μ†Œλ©Έ

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

 

상속 κ΄€κ³„μ—μ„œ μƒμ„±λ˜λŠ” μΈμŠ€ν„΄μŠ€μ˜ μœ ν˜• 쀑 λ‹€ν˜•μ„±μ„ 기반으둜 λ§Œλ“€μ–΄μ§„ μΈμŠ€ν„΄μŠ€λŠ” 보톡 νŒŒμƒν΄λž˜μŠ€(Derived Class)λ₯Ό 톡해 κΈ°λ³Έ 클래슀(Base Class)λ₯Ό μ΄ˆκΈ°ν™”ν•©λ‹ˆλ‹€. 상속 κ΄€κ³„μ—μ„œ νŒŒμƒ 클래슀의 μΈμŠ€ν„΄μŠ€λ₯Ό λ§Œλ“ λ‹€ ν•˜λ”λΌλ„ λ‚΄λΆ€μ μœΌλ‘œλŠ” κΈ°λ³Έ 클래슀의 μΈμŠ€ν„΄μŠ€κΉŒμ§€ λ§Œλ“€μ–΄μ§€μ§€λ§Œ κΈ°λ³Έ 클래슀의 μƒμ„±μžλŠ” μž„μ˜λ‘œ ν˜ΈμΆœν•  수 μ—†κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€.

λ°˜λŒ€λ‘œ μΈμŠ€ν„΄μŠ€μ˜ μ†Œλ©Έλ„ λ§ˆμ°¬κ°€μ§€μž…λ‹ˆλ‹€. νŒŒμƒ 클래슀만 μ†Œλ©Έν•˜κ³  κΈ°λ³Έ 클래슀의 μ˜μ—­μ΄ μ†Œλ©Έλ˜μ§€ μ•ŠμœΌλ©΄ λ©”λͺ¨λ¦¬ λˆ„μˆ˜(Memory Leak)κ°€ λ°œμƒν•  κ°€λŠ₯성이 있기 λ•Œλ¬Έμ— 이 λ˜ν•œ νŒŒμƒ ν΄λž˜μŠ€μ—μ„œ μ±…μž„μ Έμ•Ό ν•©λ‹ˆλ‹€.

 

 

μƒμ„±μž(Contructor)

κΈ°λ³Έ ν΄λž˜μŠ€(Base Class)의 μƒμ„±μž ν˜ΈμΆœ: νŒŒμƒ ν΄λž˜μŠ€(Derived Class)의 μƒμ„±μžκ°€ ν˜ΈμΆœλ˜κΈ° μ „에 λ¨Όμ € κΈ°λ³Έ ν΄λž˜μŠ€μ˜ μƒμ„±μžκ°€ ν˜ΈμΆœλ©λ‹ˆλ‹€. κΈ°λ³Έ ν΄λž˜μŠ€μ˜ μƒμ„±μžλŠ” ν•΄λ‹Ή ν΄λž˜μŠ€μ˜ λ©€λ²„ λ³€μˆ˜ λ° κΈ°νƒ€ μ΄ˆκΈ°ν™”λ₯Ό λ‹΄λ‹Ήν•©λ‹ˆλ‹€. κΈ°λ³Έ ν΄λž˜μŠ€μ˜ μƒμ„±μž ν˜ΈμΆœμ€ νŒŒμƒ ν΄λž˜μŠ€μ˜ μƒμ„±μžμ˜ μ΄ˆκΈ°ν™” λͺ©λ‘(initialization list)μ—μ„œ μˆ˜ν–‰λ©λ‹ˆλ‹€.

νŒŒμƒ 클래슀(Derived Class)의 μƒμ„±μž 호좜: κΈ°λ³Έ ν΄λž˜μŠ€μ˜ μƒμ„±μž ν˜ΈμΆœμ΄ μ™„λ£Œλ˜λ©΄, νŒŒμƒ ν΄λž˜μŠ€μ˜ μƒμ„±μžκ°€ ν˜ΈμΆœλ©λ‹ˆλ‹€. νŒŒμƒ ν΄λž˜μŠ€μ˜ μƒμ„±μžλŠ” κΈ°λ³Έ ν΄λž˜μŠ€μ˜ μƒμ„±μž ν˜ΈμΆœ ν›„에 μ‹€ν–‰λ˜λŠ” μ½”λ“œλ₯Ό ν¬ν•¨ν•©λ‹ˆλ‹€. μ΄ μ½”λ“œλŠ” νŒŒμƒ ν΄λž˜μŠ€μ˜ λ©€λ²„ λ³€μˆ˜λ₯Ό μ΄ˆκΈ°ν™”ν•˜κ±°λ‚˜ μΆ”가적인 μž‘업을 μˆ˜ν–‰ν•˜λŠ” λ° μ‚¬μš©λ©λ‹ˆλ‹€.

상속 κ΄€κ³„μ—μ„œ νŒŒμƒ ν΄λž˜μŠ€μ˜ μƒμ„±μžλŠ” κΈ°λ³Έ ν΄λž˜μŠ€μ˜ μƒμ„±μžλ₯Ό ν˜ΈμΆœν•΄μ•Ό ν•©λ‹ˆλ‹€. μ΄λ ‡κ²Œ ν•˜λ©΄ κΈ°λ³Έ ν΄λž˜μŠ€μ˜ λ©€λ²„ λ³€μˆ˜κ°€ μ˜¬λ°”λ₯΄κ²Œ μ΄ˆκΈ°ν™”λ˜κ³ , νŒŒμƒ ν΄λž˜μŠ€μ˜ μƒμ„±μžμ—μ„œλŠ” ν•΄λ‹Ή ν΄λž˜μŠ€μ— νŠΉν™”λœ μž‘업을 μˆ˜ν–‰ν•  μˆ˜ μžˆμŠ΅λ‹ˆλ‹€.

class Base {
private:
	int baseValue;
public:
    Base(int value) : baseValue(value) 
    {
        // κΈ°λ³Έ 클래슀 μƒμ„±μžμ˜ μ½”λ“œ
        // 멀버 λ³€μˆ˜ μ΄ˆκΈ°ν™” 등을 μˆ˜ν–‰
    }
};

class Derived : public Base {
private:
	int derivedValue;
public:
    Derived(int value1, int value2) : Base(value) 
    {
    	derivedValue = value2;
        // νŒŒμƒ 클래슀 μƒμ„±μžμ˜ μ½”λ“œ
        // 멀버 λ³€μˆ˜ μ΄ˆκΈ°ν™” 및 μΆ”κ°€ μž‘μ—… μˆ˜ν–‰
    }
};

μœ„ κ°„λ‹¨ν•œ μ˜ˆμ œμ—μ„œ, μžμ‹ 클래슀(νŒŒμƒ 클래슀)λŠ” 2개의 μƒμ„±μž 인자λ₯Ό λ°›κ³  그쀑 ν•˜λ‚˜λŠ” λΆ€λͺ¨ 클래슀(κΈ°λ³Έ 클래슀)의 μƒμ„±μžλ₯Ό ν˜ΈμΆœν•˜λ©°, λ‚˜λ¨Έμ§€ ν•˜λ‚˜λŠ” μžμ‹ μ΄ μ‚¬μš©ν•©λ‹ˆλ‹€. λ§Œμ•½ λΆ€λͺ¨ 클래슀의 μƒμ„±μžλ₯Ό μžμ‹ ν΄λž˜μŠ€μ—μ„œ μ±…μž„μ§€μ§€ μ•ŠλŠ”λ‹€λ©΄, λΆ€λͺ¨ 클래슀의 μƒμ„±μžλ₯Ό ν˜ΈμΆœν•  수 μžˆλŠ” 방법은 μ—†μŠ΅λ‹ˆλ‹€.

 

λ¬Όλ‘ , λΆ€λͺ¨ν΄λž˜μŠ€μ˜ μƒμ„±μžμ—μ„œ ν•΄μ•Όν•˜λŠ” 일을 initκ³Ό 같은 ν•¨μˆ˜λ₯Ό λ§Œλ“€μ–΄μ„œ ν˜ΈμΆœν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ–΄λ””κΉŒμ§€λ‚˜ μƒμ„±μžμ˜ μ΄μ•ΌκΈ°μž…λ‹ˆλ‹€. λŒ€λΆ€λΆ„μ˜ λ©€λ²„λ³€μˆ˜μ˜ μ΄ˆκΈ°ν™”λŠ” μƒμ„±μžκ°€ 맑고 있기 λ•Œλ¬Έμ— μœ„μ™€ 같이 λΆ€λͺ¨ 클래슀의 μƒμ„±μž 호좜이 맀우 μΌλ°˜μ μž…λ‹ˆλ‹€.

 

 

μ†Œλ©Έμž(Destructor)

νŒŒμƒ ν΄λž˜μŠ€(Derived Class)의 μ†Œλ©Έμž ν˜ΈμΆœ: κ°μ²΄κ°€ νŒŒκ΄΄λ˜λŠ” μ‹œμ μ— νŒŒμƒ ν΄λž˜μŠ€μ˜ μ†Œλ©Έμžκ°€ ν˜ΈμΆœλ©λ‹ˆλ‹€. μ†Œλ©ΈμžλŠ” ν•΄λ‹Ή ν΄λž˜μŠ€μ˜ κ°μ²΄κ°€ μ†Œλ©Έλ  λ•Œ ν•„μš”ν•œ μ •λ¦¬ μž‘업을 μˆ˜ν–‰ν•©λ‹ˆλ‹€. νŒŒμƒ ν΄λž˜μŠ€μ˜ μ†Œλ©ΈμžλŠ” νŒŒμƒ ν΄λž˜μŠ€μ— μΆ”κ°€λœ λ©€λ²„ λ³€μˆ˜ λ˜λŠ” μžμ›μ„ ν•΄μ œν•˜λŠ” λ“±μ˜ μž‘업을 μˆ˜ν–‰ν•  μˆ˜ μžˆμŠ΅λ‹ˆλ‹€.

κΈ°λ³Έ ν΄λž˜μŠ€(Base Class)의 μ†Œλ©Έμž ν˜ΈμΆœ: νŒŒμƒ ν΄λž˜μŠ€μ˜ μ†Œλ©Έμž ν˜ΈμΆœμ΄ μ™„λ£Œλ˜λ©΄, κΈ°λ³Έ ν΄λž˜μŠ€μ˜ μ†Œλ©Έμžκ°€ ν˜ΈμΆœλ©λ‹ˆλ‹€. κΈ°λ³Έ ν΄λž˜μŠ€μ˜ μ†Œλ©ΈμžλŠ” ν•΄λ‹Ή ν΄λž˜μŠ€μ˜ κ°μ²΄κ°€ μ†Œλ©Έλ  λ•Œ ν•„μš”ν•œ μ •λ¦¬ μž‘업을 μˆ˜ν–‰ν•©λ‹ˆλ‹€. κΈ°λ³Έ ν΄λž˜μŠ€μ˜ μ†Œλ©ΈμžλŠ” νŒŒμƒ ν΄λž˜μŠ€μ˜ μ†Œλ©Έμžμ—μ„œ λͺ…μ‹œμ μœΌλ‘œ ν˜ΈμΆœλ˜μ§€ μ•Šλ”라도 μžλ™μœΌλ‘œ ν˜ΈμΆœλ©λ‹ˆλ‹€.

상속 κ΄€κ³„μ—μ„œ κ°μ²΄μ˜ μ†Œλ©Έμ€ νŒŒμƒ ν΄λž˜μŠ€μ—μ„œλΆ€ν„° μ‹œμž‘ν•˜μ—¬ κΈ°λ³Έ ν΄λž˜μŠ€κΉŒμ§€ κ±°μŠ¬λŸ¬ μ˜¬λΌκ°€λ©° μ†Œλ©Έμžκ°€ ν˜ΈμΆœλ˜λŠ” λ°˜λŒ€ μˆœμ„œλ‘œ μ§„ν–‰λ©λ‹ˆλ‹€. μ΄λ₯Ό "μ—­μˆœ μ†Œλ©Έ(reverse order of destruction)"이라고도 ν•©λ‹ˆλ‹€. μ΄ μˆœμ„œλŠ” κ°μ²΄κ°€ μƒμ„±λ  λ•Œμ™€λŠ” λ°˜λŒ€λ‘œ, κΈ°λ³Έ ν΄λž˜μŠ€μ˜ μ†Œλ©Έμžκ°€ λ¨Όμ € ν˜ΈμΆœλ˜κ³  νŒŒμƒ ν΄λž˜μŠ€μ˜ μ†Œλ©Έμžκ°€ λ‚˜μ€‘에 ν˜ΈμΆœλ˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

class Base {
private:
	int* ptr[64];
public:
    Base() {
        // κΈ°λ³Έ 클래슀 μƒμ„±μž μ½”λ“œ
    }
    ~Base() {
    	delete ptr[];
        // κΈ°λ³Έ 클래슀 μ†Œλ©Έμž μ½”λ“œ
    }
};

class Derived : public Base {
public:
    Derived() {
        // νŒŒμƒ 클래슀 μƒμ„±μž μ½”λ“œ
    }
    ~Derived() {
        // νŒŒμƒ 클래슀 μ†Œλ©Έμž μ½”λ“œ
    }
};

μœ„μ˜ μ˜ˆμ‹œμ—μ„œ Derived ν΄λž˜μŠ€λŠ” Base ν΄λž˜μŠ€λ₯Ό μƒμ†ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. κ°μ²΄κ°€ μ†Œλ©Έλ  λ•ŒλŠ” ~Derived()κ°€ λ¨Όμ € ν˜ΈμΆœλ˜κ³ , κ·Έ ν›„에 ~Base()κ°€ ν˜ΈμΆœλ©λ‹ˆλ‹€. μ΄λ ‡κ²Œ ν•¨μœΌλ‘œμ¨ νŒŒμƒ ν΄λž˜μŠ€μ˜ μ†Œλ©Έμžμ—μ„œ μΆ”가적인 μ •λ¦¬ μž‘업을 μˆ˜ν–‰ν•œ ν›„, κΈ°λ³Έ ν΄λž˜μŠ€μ˜ μ†Œλ©Έμžμ—μ„œ ν•΄λ‹Ή ν΄λž˜μŠ€μ˜ μžμ›μ„ ν•΄μ œν•  μˆ˜ μžˆμŠ΅λ‹ˆλ‹€.

 

 

 

λ‹€ν˜•μ„± κ΄€κ³„μ—μ„œμ˜ 가상 μ†Œλ©Έμž(Virtual Destructor)

C++μ—μ„œ κ°€μƒ μ†Œλ©Έμž(virtual destructor)λŠ” κΈ°λ³Έ ν΄λž˜μŠ€μ— λŒ€ν•œ ν¬μΈν„°λ‚˜ μ°Έμ‘°λ₯Ό μ‚¬μš©ν•˜μ—¬ νŒŒμƒ ν΄λž˜μŠ€ κ°μ²΄λ₯Ό λ‹€λ£° λ•Œ μ€‘μš”ν•œ μ—­ν• μ„ ν•©λ‹ˆλ‹€. νŒŒμƒ ν΄λž˜μŠ€μ˜ μ†Œλ©Έμžλ₯Ό κ°€μƒ μ†Œλ©Έμžλ‘œ μ„ μ–Έν•˜λ©΄, λ™μ  ν• λ‹Ήλœ κ°μ²΄λ₯Ό μ œλŒ€λ‘œ μ†Œλ©Έμ‹œν‚€κ³  λ©”λͺ¨λ¦¬ λˆ„μˆ˜(memory leaks)λ₯Ό λ°©μ§€ν•  μˆ˜ μžˆμŠ΅λ‹ˆλ‹€.

κ°€μ •ν•΄ λ΄…μ‹œλ‹€. κΈ°λ³Έ ν΄λž˜μŠ€μ— λŒ€ν•œ ν¬μΈν„°λ‘œ νŒŒμƒ 클래슀 객체λ₯Ό 가리킀고 μžˆλŠ” μƒν™©μ—μ„œ νŒŒμƒ 클래슀의 객체λ₯Ό μ‚­μ œν•˜λ €κ³  ν•©λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ κΈ°λ³Έ 클래슀의 μ†Œλ©Έμžκ°€ 가상이 μ•„λ‹Œ 경우(κΈ°λ³Έ 클래슀의 μ†Œλ©Έμžκ°€ virtual이 μ•„λ‹Œ 경우), νŒŒμƒ 클래슀의 μ†Œλ©Έμžκ°€ ν˜ΈμΆœλ˜μ§€ μ•Šμ„ 수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŠ” νŒŒμƒ 클래슀의 멀버 λ³€μˆ˜ λ˜λŠ” λ™μ μœΌλ‘œ ν• λ‹Ήλœ λ©”λͺ¨λ¦¬ 등이 μ μ ˆν•˜κ²Œ ν•΄μ œλ˜μ§€ μ•ŠλŠ” 문제λ₯Ό μ΄ˆλž˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

λ‹€μŒμ€ virtual μ†Œλ©Έμžλ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šμ€ μ˜ˆμ‹œ μ½”λ“œμž…λ‹ˆλ‹€.

#include <iostream>

class Base {
public:
    Base() {
    	std::cout << "Base()" << endl;
        // κΈ°λ³Έ 클래슀 μƒμ„±μž μ½”λ“œ
    }
    ~Base() {
    	std::cout << "~Base()" << endl;
        // κΈ°λ³Έ 클래슀 μ†Œλ©Έμž μ½”λ“œ
    }
};

class Derived : public Base {
public:
    Derived() {
    	std::cout << "Derived()" << endl;
        // νŒŒμƒ 클래슀 μƒμ„±μž μ½”λ“œ
    }
    ~Derived() {
    	std::cout << "~Derived()" << endl;
        // νŒŒμƒ 클래슀 μ†Œλ©Έμž μ½”λ“œ
    }
};

int main() {
    Base* ptr = new Derived();
    delete ptr; // λ¬Έμ œκ°€ λ°œμƒν•  수 있음
    return 0;
}

/* μ‹€ν–‰κ²°κ³Ό
Base()
Derived()
~Base()
*/

 

μœ„μ˜ μ˜ˆμ‹œμ—μ„œ ptr은 Base ν΄λž˜μŠ€μ˜ ν¬μΈν„°μ§€λ§Œ, μ‹€μ œλ‘œ Derived ν΄λž˜μŠ€μ˜ κ°μ²΄λ₯Ό κ°€λ¦¬ν‚€κ³  μžˆμŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ Base ν΄λž˜μŠ€μ˜ μ†Œλ©Έμžκ°€ κ°€μƒμ΄ μ•„λ‹ˆκΈ° λ•Œλ¬Έμ— delete ptr λ¬Έμž₯이 μ‹€ν–‰λ  λ•Œ νŒŒμƒ ν΄λž˜μŠ€μΈ Derived의 μ†Œλ©Έμžκ°€ ν˜ΈμΆœλ˜μ§€ μ•Šμ„ μˆ˜ μžˆμŠ΅λ‹ˆλ‹€. μ΄λŠ” Derived ν΄λž˜μŠ€μ—μ„œ λ™μ μœΌλ‘œ ν• λ‹Ήλœ λ©”λͺ¨λ¦¬ λ˜λŠ” μΆ”가적인 μ •λ¦¬ μž‘업이 μ œλŒ€λ‘œ μ΄λ£¨μ–΄μ§€μ§€ μ•ŠλŠ” λ¬Έμ œλ₯Ό μ΄ˆλž˜ν•  μˆ˜ μžˆμŠ΅λ‹ˆλ‹€.

λ”°λΌμ„œ Base ν΄λž˜μŠ€μ˜ μ†Œλ©Έμžμ— virtual을 λΆ™μ—¬ κ°€μƒ μ†Œλ©Έμžλ‘œ μ„ μ–Έν•΄μ•Ό ν•©λ‹ˆλ‹€:

#include <iostream>

class Base {
public:
    Base() {
    	std::cout << "Base()" << endl;
        // κΈ°λ³Έ 클래슀 μƒμ„±μž μ½”λ“œ
    }
    virtual ~Base() {
    	std::cout << "~Base()" << endl;
        // κΈ°λ³Έ 클래슀 μ†Œλ©Έμž μ½”λ“œ
    }
};

class Derived : public Base {
public:
    Derived() {
    	std::cout << "Derived()" << endl;
        // νŒŒμƒ 클래슀 μƒμ„±μž μ½”λ“œ
    }
    ~Derived() {
    	std::cout << "~Derived()" << endl;
        // νŒŒμƒ 클래슀 μ†Œλ©Έμž μ½”λ“œ
    }
};

int main() {
    Base* ptr = new Derived();
    delete ptr; // λ¬Έμ œκ°€ λ°œμƒν•  수 있음
    return 0;
}

/* μ‹€ν–‰κ²°κ³Ό
Base()
Derived()
~Derived()
~Base()
*/

Base ν΄λž˜μŠ€μ˜ μ†Œλ©Έμžλ₯Ό virtual둜 μ„ μ–Έν•˜λ©΄, delete ptr λ¬Έμž₯이 μ‹€ν–‰λ  λ•Œ Derived ν΄λž˜μŠ€μ˜ μ†Œλ©Έμžκ°€ μ˜¬λ°”λ₯΄κ²Œ ν˜ΈμΆœλ©λ‹ˆλ‹€. μ΄λ‘œμ¨ Derived ν΄λž˜μŠ€μ—μ„œ λ™μ  ν• λ‹Ήλœ λ©”λͺ¨λ¦¬ λ˜λŠ” μΆ”가적인 μ •λ¦¬ μž‘업을 μ μ ˆν•˜κ²Œ μˆ˜ν–‰ν•  μˆ˜ μžˆκ²Œ λ©λ‹ˆλ‹€.

 

 

λŒ“κΈ€