참조 : 전문가를 위한 C++ 개정 5판

사용 주의 점

  • 다중 상속 사용 시, 중복 상속 주의
    • virtual 상속으로 방지하기
  • 부모 클래스는 virtual 소멸자 지정하기
    • 소멸자에 virtaul 키워드가 없으면 자식의 소멸자 실행 안될 수 있음
  • 부모 클래스의 생성자, 소멸자 자동 호출
  • void 매개변수 함수는 오버로딩 시, 보이드 함수가 가려짐
    • 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

+ Recent posts

let textNodes = document.querySelectorAll("div.tt_article_useless_p_margin.contents_style > *:not(figure):not(pre)"); textNodes.forEach(function(a) { a.innerHTML = a.innerHTML.replace(/`(.*?)`/g, '$1'); });