개발 Study

#30. 오버라이딩, virtual, 객체포인터

HYuk 2021. 5. 13. 16:52
728x90

#상속 관계에서 생성자와 소멸자

상속 관계에서 생성자와 소멸자는 아래와 같이 이루어 진다.

 

부모클래스 생성자 -> 자식클래스 생성자 -> 자식클래스 소멸자 -> 부모클래스 소멸자

순으로 생성자와 소멸자가 생성된다.

 

메모리 할당 순서까지 확인해보면

객체 생성 -> 메모리 할당 -> 부모 생성자 호출 -> 자식 생성자 호출

-> 자식 소멸자 호출 -> 부모 소멸자 호출 -> 메모리 반환 -> 객체 소멸

순이다.

 

#객체포인터

객체 자신의 주소 또는 자신을 직/간접 상속받는 객체의 주소를 저장할 수 있다.

부모클래스* AA = new 부모클래스; -> 가능

부모클래스* AA2 = new 자식클래스; ->가능

자식클래스* AA3 = new 부모클래스; -> 불가능

 

 

#오버라이딩

상속관계에서 부모클래스의 멤버함수를 자식클래스에서 재정의 하는것을 오버라이딩이라고 한다.

함수 정의를 할 때, 반환 타입, 함수 이름, 매개변수 정보가 변하지 않는다.

둘다 Func()라고 가정 할 때,

부모클래스* ptr = new 자식클래스;

ptr->Func();

를 했을때 타입 기준의 함수 즉 부모클래스의 Func가 나오게 된다.


#가상함수 (virtual)

가상함수는 클래스를 번역하면서 virtual이 있으면 가상함수 테이블을 만든다

그 테이블(배열형식)에 가상함수들을 저장하고

그 주소를 가지는 가상함수포인터를 멤버로 추가한다.

 

따라서 함수만 가지고 있는 경우 클래스의 크기는 1byte이고

가상함수를 가지고 있는 클래스의 크기는 4byte로 나오게 된다.

 

가상함수는 상속에도 적용이 되는데

부모클래스 virtual void Func() / 자식클래스 void Func()

있을경우

자식클래스의 Func도 virtual 화 된다.

 

virtual은 처음 불러올때 없는 취급을 하다가 없으면 가상함수포인터의 주소를 불러오는 형식으로 작동이 된다.

 

위의 오버라이딩에서

부모클래스* ptr = new 자식클래스;

ptr->Func();

일 경우

ptr은 부모클래스 타입이라 부모클래스의 Func()를 불러왔지만,

virtual을 적용하게 되면 기존의 생성자와 소멸자 순으로 Func을 확인하게 된다.

부모생성->자식생성->자식생성->자식소멸

순인데

1. 이때 처음 부모클래스의 Func을 확인하고 virtual 화 되어있어서

2. 자식 Func을 확인하고 virtual 화 되어있어서

3. 자식 가상함수포인터의 주소를 참조하게 된다.

따라서 위와 같은경우 virtual 함수를 부를때 자식 클래스의 Func()를 부르게 된다.

 

사용방법

반환타입 앞에 virtual을 붙이면 된다.

ex) virtual void Func();

 

#순수가상함수

순수 가상함수는 부모클래스에서 함수 앞에 virtual을 붙이고 정의부를 구현 안한 것을 말한다.

이 가상함수는 선언부 끝에 =0을 붙여서 사용 할 수 있다.

무조건적으로 자식클래스에서 다형성을 이용하여 사용하게 하기 위함이다

virtual void Func()=0; 으로 선언하면 된다.

-> 순수 가상함수를 단 하나라도 가지고 있는 클래스(추상클래스)의 경우 객체를 생성할 수 없다.

이때 자식클래스에서 오버라이딩을 하지 않을경우 순수 가상함수를 상속받아

자식클래스에서도 객체를 생성할 수 없게 된다

 


#객체 포인터의 문제점

상속관계에서

부모클래스* ptr = new 자식클래스;

를 하면 부모클래스 생성자 및 자식클래스 생성자가 정상적으로 나오게 된다.

다 사용하고 난 뒤

delete ptr;

을 할 경우

ptr은 부모클래스의 형식이기 때문에 부모클래스의 소멸자만 호출이 되고 끝이 나버린다.

이때 virtual을 부모소멸자에 사용하게 되면 위의 virtual 의 방식대로 자식소멸자 -> 부모소멸자 모두 정상적으로 호출되게 된다.

728x90