일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- go channel
- go
- C++ gui
- BOJ
- gui
- 자료구조
- tour of go
- 코딩
- C언어
- LOB
- vim-go
- C++
- 운영체제
- 연결리스트
- 리듬게임
- JUCE
- C++ gui 라이브러리
- JUCE 튜토리얼
- 알고리즘
- JUCE라이브러리
- OS
- c++ heap
- Nebula
- 백준
- 공룡책
- 프로그래밍
- JUCE library
- C++ library
- a tour of go
- Docker
- Today
- Total
CafeM0ca
[C++]상속 (virtual, override, static) 본문
virtual 키워드는 클래스간 상속에서 자식 클래스가 부모 클래스의 함수를 오버라이딩 특성을 제어하고자 할 때 사용한다.
묻따말 코드부터 보자
출력결과
부모 클래스로 Super가 있고 자식 클래스로 Sub은 public으로 Super를 상속하는데
잠시 삼천포로 빠져 접근지시자에 대한 설명을 하자면
public으로 상속받으면 Super에 public멤버에 접근 가능하다. 나머지는 다 private
private |
부모 클래스의 public,protected,private가 private로 바뀜 |
protected |
부모 클래스의 private,protected가 private로 바뀜 |
public |
부모클래스의 private가 private로 바뀜 |
즉 public으로 상속받으면 protected까지 접근 가능하다는 이야기다.
Sub함수가 Super함수의 foo를 재정의했다.(overriding. 오버로딩이랑 햇갈리지 말자)
물론 Sub함수가 Super의 foo를 호출 할 수 있다.
Super클래스에 주석친 부분을 보면 final 키워드가 있다. 이는 자식클래스가 해당 함수를 오버라이딩을 막기위한 것이다.
C++에서 객체를 생성하는 순서는 다음과 같다.
1. 부모 객체
2. 자기 자신
3. 멤버 변수
기본적으로 상속 메커니즘은 자식 객체가 되기 위해 부모 객체에서 살을 덧붙인 형태이다.
부모 객체가 60byte의 크기고
자식 객체가 80byte면.
일단 메모리상에 부모 객체 60byte가 올라간 후, 자식 객체의 20byte만큼을 덧붙이는 형태이다.
그럼 아래와 같은 코드는 어떨까?
spref가 sb를 참조하고 있다. 직관적으로 확인해보자
대충 이런 형태로 참조하고 있다.
따라서 spref가 foo를 호출하면 Super의 foo가 호출된다.
그럼 Sub의 foo를 호출할 방법은 없는거같지만 virtual 키워드를 붙여주면 가능하다.
결과
C++11부터는 override 키워드가 생겼다. 자식 클래스가 부모 클래스의 함수 시그니쳐(이름)와 동일한 함수를 선언하고 딴짓하는것을 막기 위해서다.
반환형, 인자, 한정자까지 꼼꼼하게 확인해주는 역할을한다.
Sub타입의 참조자가 Super클래스를 가리키는건 안된다.
+ 전문가를 위한 C++에서는 파생 클래스 조차도 virtual 키워드를 붙여주라고한다. (성능은 떨어지지만 위험성은 낮아진다고 . .)
+ 부모 클래스에서 가상함수의 시그니쳐만 있고 구현부가 없는것을 순수(pure) 가상 함수라고한다. 반드시 파생 클래스에서 재정의 되어야한다. (추상화를 위해 이렇게 사용한다. 사용법은 정의부분에서 virtual func() = 0;)
using 키워드를 사용한 상속
sub2는 Super의 생성자를 호출 할 수 없다. 호출하고 싶으면 다음과 같이 using키워드를 이용해 명시적으로 Super 생성자의 상속을 선언할 수 있다.
using으로 생성자를 상속받을 때는 몇 가지 제약 사항이 있다.
1. 생성자를 선택적으로 상속받을 수 없다.
2. 다중 상속받은 베이스 클래스들 중 같은 파라미터 목록의 생성자를 가진 경우가 있다면 생성자를 상속 받을 수 없다. (어느쪽 부모를 호출해야할지 모르기 때문에 모호함. 다중 상속을 할 경우 가상 기초 클래스로 만들자. 모호성을 없앨 수 있다.)
다음과 같은 코드는 Sub클래스가 Super의 overload(int i) 함수를 사용할 수 있게 해준다.
메서드를 오버라이딩할 때 서로 다른 파라미터로 정의된 해당 메서드의 모든 버전을 오버라이딩하거나 using 키워드를 이용해 명시적으로 선언해주자.
C++에서는 static 메서드를 오버라이딩할 수 없다.
- static이면서 virtual일 수 없다.
- 베이스 클래스에 vstatic void foo(); 함수가 있고 파생 클래스에 static void foo(); 함수가 있으면 이 둘은 독립적인 것이다.
접근지시자 트릭
Gregarious(사교적인) 클래스의 talk는 public이지만 그것을 상속하여 오버로딩한 Shy는 protected다.
Shy에서 talk는 protected이므로 호출이 불가능하다.
그러나 Gregarious의 참조자나 포인터로 talk를 호출하면 가능하다.
+ 이해가 덜 돼서 나중에 추가
RTTI(run time type information)는 객체가 속한 클래스와 연동되는 여러 가지 기능을 제공한다.
dynamic_cast가 그중 한가지다. 객체간의 타입 변환을 안전하게 해준다.
typeid라는 연산자도 있는데 두 객체의 타입이 같은지 알려주는 연산자다.
#include <typeinfo>
void speak(const Animal& inAnimal)
{
if (typeid(inAnimal) == typeid(Dog&)) {
cout << "Woof!' << endl;
}
else if (typeid(inAnimal) == typeid(Bird&)) {
cout << "Chirp!" << endl;
}
}
'Programming > C++' 카테고리의 다른 글
[C++] constexpr (0) | 2018.07.09 |
---|---|
[C++] rvalue reference(우측값) (0) | 2018.07.09 |
[C++] pimpl(pointer to implementation) (0) | 2018.06.30 |
[C++] dangling pointer (0) | 2018.06.30 |
[C++] 클래스에서 default와 delete (0) | 2018.06.30 |