clas CObj{
int m_iA;
}
class Cchild : public CObj
{
int m_iA; => this.m_iA;(보통은 자식에서 부르면 자식의 것)
//부모꺼는 CObj::m_iA;
}
자식 / 부모 생성할 때, 부모 클래스 전방 선언이 불가함.(헤더파일 포함해야 함) 객체 생성은 헤더파일이 없이는 어렵다..? 확인완료 (맞음→ 컴파일 오류남)
자식 개체의 생성 과정
- 메모리 할당
- 부모 생성자 호출
- 자식 생성자 호출
자식 개체의 소멸 과정
- 자식 소멸자 호출
- 부모 소멸자 호출
- 메모리 반환
정확한 용어 (기반 클래스 / 파생 클래스)
Is a
Penguin Is a animal A는 일종의 B이다. → 사람과 동물의 관계
<====== 일반화
⇒
========> 구체화
Has a
Player Has a Sword; A는 B를 가진다. A는 B를 포함한다. → 비행기와 엔진의 관계
IS A 관계가 상속의 핵심이라고 할 수 있다.
정적 바인딩 : static binding ⇒ 컴파일 타임에 호출하는 것이 결정된 함수 동적 바인딩 : dynamic binding ⇒ 런타임 중에 호출하는 것이 결정된 함수
CObj* pPlayer = new Player();
→ Player안에만 있는 함수를 호출할 수 없는 형태 (오버라이딩이 없다면)
다형성 : 다형성 문법은 포인터 타입으로만 가능
부모 객체를 이용해서 여러가지 형태(자식 개체)로 사용하는 방식 다형성을 표현하는 방식
- 오버라이딩
- 다운캐스팅(dynamic_cast) 자식 개체만 가지고 있고, 다른 자식개체와는 통일성이 없는 것이 있을 때 사용
오버로딩 : 함수의 문법 오버라이드 : 클래스의 문법
오버라이딩의 규칙
- 상속 관계여야 한다.
- 부모자식의 함수가 이름/반환타입/매개변수 일치해야 한다.
- 부모의 함수 앞에 virtual 키워드를 사용한다.
==가상 함수의 동작 원리== : 오로지 가상함수 포인터/테이블로만 호출됨
virtual 키워드가 붙게 되면 가상함수 테이블이 생성되며, 그 가상 함수 테이블을 기록하는 포인터가 생겨나기 때문에 용량이 늘어난다. (포인터니까 8바이트 추가)
vptr → 가상 함수 포인터 (8바이트)
vtbl → 가상 함수 테이블 : 가상 함수들의 주소를 저장하는 테이블
용량을 계산할 때 포함하지는 않지만, 최소 8. (주소를 저장하는 거니까)
객체는 가상함수 포인터를 통해서 테이블에 접근하고 접근한 테이블에서 함수를 호출하기 때문에 일반 함수보다는 더 느리게 호출한다.
주의! 자식 개체는 부모 개체가 가상함수가 생기면서 가상함수 포인터를 가지게 된다. (용량 계산을 할 때 두개 다 8바이트가 나오는 이유는 부모가 8바이트라서 그런 것이 아니다.)
왜냐면, 부모의 virtual함수가(키워드가) 자식에게도 상속되면서 자식 또한 자신의 가상 함수 포인터와 가상함수 테이블을 생성하게 된다.
오버라이딩의 재정의 : 상위 클래스에 정의된 메서드의 구현 내용이 하위 클래스에서 구현할 내용과 맞지 않는 경우 하위 클래스에서 동일한 이름의 메서드를 재정의 할 수 있음
오버라이딩의 은닉화 : 다형성을 쓸 때 부모 타입으로 자식 개체를 포인터 타입으로 부르게 되면, 그 포인터 타입은 부모 자료형으로 자식의 개체를 가리키게 되면서 부모의 가상함수 포인터가 자식의 가상함수 포인터에 의해 가려진다. 이것이 은닉화.
그래서 부모 타입으로 자식의 가상함수를 호출할 수 있게 된것!!!!
가상함수와 가상함수 테이블이 “생성”되는 것은 : 정적 바인딩(컴파일 타임에 정해짐) 부모 타입으로 자식의 객체를 포인터로 가리키면서 함수를 “호출”하는 것 : 동적바인딩 → 어떤 테이블을 참조할 것인가? 이게 런타임
가상함수 포인터와 테이블은 “같은 자료형”이 공유한다. (마치 static 같네) 즉 객체를 여러개 만들어도 같은 것을 공유한다는 뜻