-
윤성우 열혈 C++ 프로그래밍 8장) 상속과 다형성(virtual 함수, virtual 소멸자, 순수 가상함수, 추상 클래스)PROGRAMMING/C++ 2024. 1. 6. 18:34
객체 지향에서 제일 중요하다는 상속과 다형성에 대해 정리해보고자 한다!
(혹시 저작권에 문제가 있다면 수정하겠습니다!! 개인적인 공부용으로 정리함을 알려드립니당)
https://product.kyobobook.co.kr/detail/S000001589147
객체 포인터 변수와 상속
AAA형 포인터 변수는 AAA 객체 또는 AAA를 직접 혹은 간접적으로 상속하는 모든 객체를 가리킬 수 있다.
👻 참조자에 대해서도 동일하게 적용된다 👻
ex) (상속관계) Person - Studen - PartimeStudent
Person * ptr1 = new Student(); Person * ptr1 = new PartTimeStudent(); Student * ptr3 = new PartTimeStudent();
함수 오버라이딩
오버라이딩된 기초 클래스의 함수는 오버라이딩을 한 유도 클래스의 함수에 가려진다.
*함수 오버로딩 : 매개변수의 자료형 및 개수가 다르면 전달되는 인자에 따라 호출되는 함수가 결정
포인터 자료형 기준
C++ 컴파일러는 포인터 연산의 가능성 여부를 판단할 때, 포인터의 자료형을 기준으로 판단하지, 실제 가리키는 객체의 자료형을 기준으로 판단하지 않는다.
ex1) (상속관계) Base - Derived
Base * bptr = new Derived(); // (o) bptr -> DerivedFunc(); // (x)
Base * bptr = new Derived(); //(o) Derived *dptr = bptr; //(x)
Derived * dptr = new Derived(); //(o) Base * bptr = dptr; //(o)
ex2) (상속관계) First - Second - Third
Third * tptr = new Third(); Second * sptr = tprt; First * fptr = sptr; tprt -> FirstFunc(); //(O) tprt -> SecondFunc(); //(O) tprt -> ThirdFunc(); //(O) sprt -> FirstFunc(); //(O) sprt -> SecondFunc(); //(O) sprt -> ThirdFunc(); //(x) fprt -> FirstFunc(); //(O) fprt -> SecondFunc(); //(x) fprt -> ThirdFunc(); //(x)
가상(Virtual) 함수
: 함수 호출시 포인터의 자료형이 아닌 포인터 변수가 실제로 가리키는 객체를 참조하여 호출의 대상이 결정된다.
- 가상함수가 하나 선언되고 나면, 이 함수를 오버라이딩 하는 함수도 가상함수가 된다.
즉, FIrst 클래스의 Func함수가 virtual로 선언되면 Second와 Third 클래스의 Func함수도 virtual로 선언된다.
- 소멸자에도 virtual을 붙여줘야 할 때가 있다.(가상 소멸자 - vritual destructor)
상속의 이유 : 상속을 통해 연관된 일련의 클래스에 대해 공통적인 규약을 정의할 수 있다.
순수 가상함수와 추상 클래스
순수 가상함수 : 함수의 몸체가 정의되지 않는 함수
추상 클래스 : 하나 이상의 멤버함수를 순수 가상함수로 선언한 클래
class A{ public: virtual void ShowInfo() const = 0; }
클래스 중에서 객체 생성을 목적으로 정의하지 않는 클래스의 경우 가상함수를 순수 가상함수로 선언하여 객체의 생성을 문법적으로 막는 것이 좋다.
다항성(Polymorphism)
: 모습은 같은데 형태는 다르다.
ex) 포인터 변수 ptr이 가리키는 객체에 동일한 함수를 실행시켜도(ptr->Func()) Base 클래스 객체인지 Derived 클래스 객체인지에 따라 같은 문장도 결과가 달라진다.
가상 소멸자(Virtual Destructor)
객체의 소멸과정에서 delete 연산자에 사용된 포인터 변수의 자료형에 상관없이 모든 소멸자가 호출되어야 할 경우 virtual 선언을 추가해준다.
- 기초 클래스의 소멸자만 virtual을 선언하면 상속되는 유도 클래스의 소멸자들도 모두 가상 소멸자로 선언된다.
- 가상소멸자 호출 시, 맨 아래 유도 클래스의 소멸자가 대신 호출되면서 기초 클래스의 소멸자가 순차적으로 호출된다.
ex) (상속관계) First - Second
First * ptr = new Second("simple", "complex"); delete ptr;
객체의 소멸을 First형 포인터에 명령하면 First 클래스의 소멸자만 호출되어 메모리 누수가 생긴다.
→ 이럴 때 가상 소멸자를 사용해야 한다!
+ 생각해보기
ex) (상속관계) First - Second - Thrid
void Func(const First &ref){//}
1. 인자 : First 객체 또는 First 객체를 상속하는 클래스 객체
2. 객체의 실제 자료형에 상관없이 First 클래스에 정의된 함수만 호출(virtual이 없으므로)
'PROGRAMMING > C++' 카테고리의 다른 글
윤성우 열혈 C++ 프로그래밍 10장) 연산자 오버로딩 1(operator+, operator++, operator-, operator--, operator<<) (1) 2024.01.07 윤성우 열혈 C++ 프로그래밍 9장) 가상의 원리와 다중상속(멤버함수의 위치, 가상함수 테이블, 가상상속) (0) 2024.01.07 윤성우 열혈 C++ 프로그래밍 7장) 상속의 이해(protected, private, public 상속) (0) 2024.01.04 윤성우 열혈 C++ 프로그래밍 6장) friend와 static 그리고 const (0) 2024.01.03 윤성우 열혈 C++ 프로그래밍 5장) 복사생성자(explicit, 임시객체) (2) 2024.01.02