참조 : 전문가를 위한 C++ 개정 5판
사용 주의 점
- 다중 상속 사용 시, 중복 상속 주의
virtual
상속으로 방지하기
- 부모 클래스는
virtual 소멸자
지정하기- 소멸자에
virtaul
키워드가 없으면 자식의 소멸자 실행 안될 수 있음
- 소멸자에
- 부모 클래스의 생성자, 소멸자 자동 호출
- void 매개변수 함수는 오버로딩 시, 보이드 함수가 가려짐
- using {부모 함수} 를 사용하여, 유지 가능
- 부모 함수의 모든 생성자를 상속 받게 됨
- using {부모 함수} 를 사용하여, 유지 가능
- 부모의 오버로드된 메서드 중 1개만 오버라이드해도, 나머지 모두 오버라이드로 간주
- 실제 부모의 다른 오버로드 메서드를 호출 시, 파생 클래스의 오버로드 메서드를 실행하기에 선언 안되었다고 에러 발생;
- 명시적으로 전부
override
하거나using
으로 해당 메서드 전부 가져오기
- 명시적으로 전부
- 실제 부모의 다른 오버로드 메서드를 호출 시, 파생 클래스의 오버로드 메서드를 실행하기에 선언 안되었다고 에러 발생;
- 업 캐스팅은 문제 x, 다운 캐스팅은 주의
- 다운 캐스팅은 부모 클래스가 자식 클래스보다 작기에 데이터 부족
dynamic_cast
사용
- static 메서드는 상속되지 않음
private
메서드는 호출이 안될 뿐,override
는 가능- 파생 클래스에서 부모 클래스의 메서드 접근권한 변경해서 사용 가능
- 부모에서
protected
->public
,public
->protected
가능 - 부모에서는 여전히 protected 지만, 파생클래스로 접근 시, 접근가능
- 부모에서
- 파생 클래스에서 복제, 대입 연산자 새롭게 정의 시, 부모 복제, 대입 연산자 정의
- 명시적으로 파생클래스에서 부모의 복제, 대입 연산자를 사용
- 디폴트 인수는 상속되지 않음
사용 방법
일반
상속 접근 제한자 : 부모의 모든 멤버의 접근제한자를 해당 접근제한이 최대치로 해서 가져옴.
메서드를 상속받을려면, 옆에 부모 클래스의 메서드 표기 (초기화 리스트보다는 항상 앞에)
class Derived : public Base { std::string s; public: Derived() : Base(), s("파생") { std::cout << "파생 클래스" << std::endl; // Base 에서 what() 을 물려 받았으므로 // Derived 에서 당연히 호출 가능하다 what(); } };
순수 가상 함수
- 반드시
override
해야함. - 이를 포함한 클래스를
추상클래스
라고 함 virtaul {function} = 0
class Animal { public: Animal() {} virtual ~Animal() {} virtual void speak() = 0; };
- 반드시
다중 상속
- 상속 여러 개 받기
- 중복 될 가능성 있는 클래스에 virtaul 키워드 붙여서 받기
using
으로 부모의 생성자를 여러개 상속 받을 떄, 겹치는 부분은 명시적으로 선언class C : public virtual public A, public B { using A::A; using B::B; C(int k); // A와 B의 (int k) 생성자 겹치는 부분 명시적으로 선언 }
virtual 과 override
virtual
키워드 사용 시, 런타임에 컴파일러가 인식하고 동적 바인딩을 실행virual 함수
는 가상 함수 테이블을 생성, 호출 시에 해당 테이블 탐색 과정이 추가- 파생 (자식)클래스는
virtaul
키워드가 없어도virtaul
상태를 유지한다 - 가상 함수 테이블의 성능 오버헤드는 미미한 편. (크게 신경써서 가독성, 유지보수성 꺠지 않기)
- 그래픽 용 클래스 (point, edge 등에는 신경쓰기)는 무수히 많이 사용하기에 주의
override
:- 11부터 사용
- 실수로 오버라이드 하지 않는 경우를 방지하기 위해 사용
- 코드 안정성과 명확성 떄문에 사용
- 사용하지 않는다고
override
안되는 거 아님
virtual 소멸자
- 자식은 본인이 상속 받는 다는 것을 알고 있기에 부모의 소멸자를 호출
- 부모는 자식이 상속 받고 있다는 것을 모르기에 본인의 소멸자 만 호출
- -> 이를 방지하기 위해 부모의 소멸자를 virtaul로 지정
공변 리턴 타입(covariant return type)
- 리턴 타입이 부모인 메서드를 오버라이드 하여, 본인 리턴타입으로 변환하는 것
- 전혀 다른 타입으로 변환은 불가
- 리스코프 치환 원칙(LIP)를 통해 확인
- 원본 메서드의 리턴 타입을 변경해도 기존 코드가 제대로 작동하는지 확인
- 부모가 사용되는 위치에 자식을 넣어도 문제가 없는지
class BingCherry { // virtual Cherry* BingCherry::Pick(); BingCherry* BingCherry::Pick() override }
unique_ptr<Cherry>
와unique_ptr<BingCherry>
는 연관이 없기에 변환 불가능
복제, 대입 연산자
- 파생 클래스에서 기본적으로 부모의 복제, 대입연산자를 파생 클래스에 맞게 변환
- 파생 클래스에서 새롭게 정의 시, 부모 복제, 대입 연산자 정의
Derived(const Derived& src) : Base { src }{}
Derived& Derived::operator=(const Derived& rhs) { if(rhs == this) { return *this; } Base::operator=(rhs); // 부모 대입 연산자 호출 // 파생 클래스 대입 연산 수행 return *this; }
'공부 > C++' 카테고리의 다른 글
참조자(&) (0) | 2025.03.14 |
---|---|
템플릿(Template) (0) | 2025.03.08 |
foreach 방식 (범위 기반 for 문) (0) | 2025.03.05 |
(C++17) optional & variant (0) | 2025.03.05 |
(C++17,20)구조적 바인딩 (0) | 2025.03.05 |