상속관계에서 접근제어자의 의미
상속받을 때 부모의 속성을 어떤 형식으로 물려받을 것이냐
class B : public A { }
- public 속성은 – 부모의 모든 것 물려받겠다. - 부모의 public 영역 다 사용하겠다.
- protected 해주면 – 부모의 public 영역을 protected로 상속받겠다. - 부모 영역 접근 불가
- private 해주면 – 부모의 public, protected영역을 private로 상속받겠다. - 부모 영역 접근 불가
다른 언어에서는 접근제어자 사용하는 경우 본 적 없다.
상속관계에서의 업 캐스팅과 다운 캐스팅
업 캐스팅
- 상속을 하게 되면 어떤 특성이 생기냐?
- 자식의 객체를 부모의 타입으로 받을 수 있다 = 업 캐스팅
일반적인 관계에서
- A타입 a객체 만들고 /// B타입 b객체 만들고
- a = b; 불가능 - ( b를 a에 대입 )
- b = a; 불가능 - ( a를 b에 대입 )
- 객체 타입이 다른 A와 B는 서로 대입 불가능
but !!
상속관계에서는
- a = b; 가능 - 업 캐스팅
- b = a; 일반적인 경우 불가능 - 다운 캐스팅
why ??
메모리 공간으로 확인해보자.
현재 메모리 상태
- A타입 a객체에 _value = 10 저장
- B타입 b객체에 _value = 20 , _value1 =30 저장되어있는 상태
a=b; 업 캐스팅 가능
- a = b; 하면 -> 부모 A타입 a객체의 _value 값이 -> 자식 B타입 b객체가 가지고 있던 value = 20으로 변경되면서 가능!
- 자식은 부모 것도 가지고 있고, 자신 것도 가지고 있으니 부모에게 대입해줄 수 있다.
b = a; 다운 캐스팅은 안된다.
- 부모인 A타입 a객체는 _value의 값만을 가지고 있는데
- 자식인 B타입 b객체는 _value와 _value1을 가지고 있다.
- 부모가 가지고 있는 값으로 자식의 모든 공간을 채워줄 수 없다.
- 일반적인 경우 부모의 클래스보다 자식 클래스가 더 많이 가지고 있으므로,
- 특별한 경우를 제외하고는 다운 캐스팅 불가능
정리
- 자식은 부모 것도 가지고 있고 자신 것도 가지고 있으니 부모에게 대입해줄 수 있지만
- 부모는 자식이 가진 것을 채워줄 자료가 없다. - 다운 캐스팅 불가능
다운 캐스팅이 가능하게 해 주려면?
객체를 받을 때 참조형이나 포인터형으로 받아야 한다.
업 캐스팅 시 ( a = b; ) 하면 대입은 되지만,
b객체의 _value1 부분이 사라진다. - 값의 유실이 생긴다 - warring 상황
그러므로!
b객체를 A타입으로 받을 경우 참조형이나 포인터형으로 받아야 한다!!
참조형이 아닌 대입( A a = b; )으로 그냥 해버리면 b객체의 유실된 값 찾을 수 없다.
참조형 / 포인터형으로 받으면 어떻게 되나 확인해보자
참조형 - 업 캐스팅 상황
30번 Line - ( a=b )가 아닌 ( &refb = b )
30번 Line - B타입 객체 b를 - A타입으로 업 캐스팅해주는데 값이 아닌 - 주소 값을 참조하는 방법으로!
30번 Line – b를 &refb로 받았으니까 &refb는 b객체 전체를 가리킨다
30번 Line – 그런데 refb를 - A타입으로 만들었으니까 b객체의 _value 부분에만 접근 가능하다.
30번 Line – b객체 전체를 가리키지만 데이터 타입 때문에 A영역인 _value에만 접근 가능
30번 Line – A타입으로 만들었다고 값이 없어진 것은 아님!
참조형 - 다운 캐스팅 상황
33번 Line - ( b=a )가 아닌 ( &refbb = (B&) refb )
33번 Line – A 타입인 &refb를 B 타입으로 형 변환 후 대입 -
33번 Line - &refb는 b객체 전체이다. B타입으로 다운 캐스팅해줘도 채워줄 수 있다. - 다운 캐스팅 가능
포인터형도 마찬가지 - 업 캐스팅 상황
38번 Line - A* => A형 주소 값을 저장하는 공간 - pb라는 변수
38번 Line - 여기에 B형 주소 값 &b 이 들어온다. - 채워 줄 수 있으므로 가능 - 업 캐스팅 가능
38번 Line - 자식 타입의 주소 값 ((( B* 의 주소 값을 저장하는 공간 )))도 pb에 들어올 수 있다.
39번 Line - pb는 b객체 전체를 가리키지만 타입이 A타입이기 때문에 - b객체의 _value 부분만 접근 가능
주소 값으로 접근 시 ( -> ) 연산자 사용
다운 캐스팅 상황
41번 Line - B* = B형 주소 값을 저장하는 공간 - pbb라는 변수에
41번 Line - 여기에 A형 주소 값 pb가 들어온다 -
41번 Line - pb는 A타입인데 (B*) B타입으로 다운 캐스팅 가능
why?
- pb가 온전한 b객체를 가리키고 있으므로 - ( 데이터 유실 X ) - 접근 가능한 부분만 달라졌던 것
- 원래 B타입이었던 애 A타입으로 갔다가 다시 돌아온 것
다시 설명
A클래스를 통해 a객체를 만들고 _value = 10;
A클래스 상속받은 B클래스를 통해 b객체를 만들고 _value = 20; , _value = 30;
객체 a와 b의 데이터 타입은 A와 B로 다르지만!
상속관계에서는 자식 타입으로 부모 타입에 적용 가능 – 업 캐스팅 가능 –언제나 허용
자식은 부모 거를 가지고 있으므로 값을 채워 줄 수 있다.
다만, 자식이 추가로 가지고 있던 부분은 값이 사라진다. - 값이 유실된다.
상속관계에서 부모 타입으로 자식 타입에 적용 불가능 – 다운 캐스팅 불가능
부모는 자식 거를 가지고 있지 않으므로 값을 채워 줄 수 없다.
a=b;
- B타입 b객체를 A타입 a에 대입하는 경우 - 업 캐스팅 가능 -채워줄 수 있으므로 가능
- a객체의 _value 값이 20으로 바뀌고 b객체가 가지고 있던 _value1의 값은 없어짐
b=a;
- A타입 a를 B타입 b에 대입하는 경우 - 다운 캐스팅 불가능 - 채워줄 수 없으므로 불가능
- b객체의 _value값은 채워줄 수 있지만 _value1의 값은 채워줄 수 없다.
이처럼 원래 B타입이었던 b객체를 값을 대입하는 형식으로 A타입으로 변경하면 데이터의 유실이 생기고
다시 B타입으로 변경하려고 하면 없어져 버린 부분 때문에 채워 줄 수 없어서 형 변환이 안된다.
이러한 상황을 만들지 않기 위해 업 캐스팅/다운 캐스팅 시에는/ 데이터의 유실을 방지하지 위해
참조형이나 포인터형으로 하는 것이 좋다.
참조형
refb 나 b 가 가리키는 것은 동일하다. - b객체 전체를 가리킨다.
But!
refb는 A타입으로 만들어진 것이다. - 그러므로 b객체의 A타입 부분만 접근 가능
포인터형
41번 Line - B타입의 객체 b의 주소 값 &b를 -> A타입 객체 주소 값 저장하는 공간 pb에 전달
41번 Line - pb는 A타입의 주소 값을 저장하는 공간이다. A*이지만 &b 가능! - 업 캐스팅 가능
41번 Line - B타입이었던 &b를 업 캐스팅- A타입 pb로 만들어줌
42번 Line - A타입인 pb는 - b객체의 A타입 부분만 접근 가능( _value1 에는 접근 불가능 )
44번 Line - 원래 B타입이었다가 A타입이 된 pb를 - 다시 B타입으로 다운 캐스팅 가능!
44번 Line – 가능한 이유 – 업 캐스팅될 시 데이터 유실 X - 온전한 B 객체를 가리키고 있던 것이다.
접근 부분만 제어되었던 것. 데이터 온전히 있으니 다시 다운 캐스팅 가능
Question.
Answer
원래는 B타입 주소 값 B* = &b
이것을 A타입 주소 갑 A* A*으로 바꾼 것이다. - 주소 값이 변한 게 아니라 타입만
이것을 다시 타입을 B타입 B*으로 바꾼 것
review
상속관계에서의 접근제어자
부모의 속성을 어떤 형식으로 물려받을 것인가를
정할 수 있는 C++의 특징!
업 캐스팅 다운 캐스팅 부분에서는
java의 묵시적 형 변환과 명시적 형 변환이 생각났다.
업캐스팅 시에는 자동으로, 다운 캐스팅시에는 명시적으로!
다른 점은 역시 C++의 참조형과 포인터형!
java에서는 다운 캐스팅 시에 논리적 오류를 잡기 위해 instance of를 사용했었는데
C++에서는 참조형과 포인터형으로 객체를 받아버리니까
체크할 필요가 없었다.
이번 강의에서 특히 좋았던 점은
"상속관계에서 업 캐스팅은 되고 다운 캐스팅은 참조형/포인터형을 사용해야 됩니다."
로 끝난 것이 아닌 객체를 값으로 받으면 다운 캐스팅이 왜 안되는지,
왜 참조형과 포인터형으로 객체를 받아야 하는 지를
내부적으로, 메모리 상황으로 알 수 있어서 좋았다.
## Check!
참조형
업 캐스팅 : A& refb = b;
다운 캐스팅 : B& refbb = (B&) refb;
포인터형
업 캐스팅 : A* pb = &b;
다운 캐스팅 : B* pbb = (B*) pb;
'Back-end > C++' 카테고리의 다른 글
22. 03. 29 - 다중 상속, 다형성 : Overloading, Override (0) | 2022.04.06 |
---|---|
22. 03. 28 - 포함 ( Compositon, Aggregation ) (0) | 2022.04.06 |
22. 03. 24 - 상속(특수화) : 동물 육성 게임, string 클래스 기능 추가 상속 (0) | 2022.04.02 |
22. 03. 23 - 캡슐화, 상속(일반화) : 동물 육성 게임 (0) | 2022.04.02 |
22. 03. 22 - 파일 분할, inline 함수 (0) | 2022.04.02 |