Home CPP Module 03 : 상속
Post
Cancel

CPP Module 03 : 상속

Ex00

문제 이해

  • energy point
    • attack, repair을 하기 위해 필요하다.
    • 스타크래프트의 미네랄과 유사한 개념
  • hit point : 체력 (hp)

Q&A

  • this 키워드를 쓰는 이유?
    • 현재 객체의 멤버 변수와 매개변수로 받은 인자의 이름구별하기 위해
  • 소멸자 개념
    1
    2
    3
    4
    5
    
      int main() {
          ClapTrap b("kim");
          b.~ClapTrap();
          std::cout << b.getName() << std::endl;
      }
    

    Untitled

    • 명시적으로 소멸자를 호출할 수 있을까? 스코프를 빠져나갈 때 소멸자가 다시 호출되는 이유?
      • 명시적으로 호출했기 때문에 소멸자가 실행된 것이고, 이후에 main 스코프를 빠져나갔기 때문에 소멸자가 다시 호출된 것이다.
      • 소멸자는 호출되는 대로 실행된다. 이전에 한번 실행했다고 이후에 실행되지 않는 것이 아니다.
    • 멤버 변수에 접근 가능한 이유?
      • 디폴트 소멸자는 객체의 메모리를 해제하는 것이 아니기 때문에 접근이 가능하다.

Ex01

주요 개념

  • virtual 키워드
    • 함수에 붙여주어 파생 클래스에서 재정의 된다는 것을 명시

Q&A

  • 상속받을 때의 접근제어자의 의미? (예. class Derived : public Base)
    • 파생 클래스에서 상속받은 기반 클래스 멤버들의 접근 제어자를 설정한다.
    • public : 기반 클래스와 접근 제어자를 동일하게 상속받음.
    • protected : public 멤버만 protected로 변경한 채로 상속받음.
    • private : 모든 멤버들을 private으로 변경한 채로 상속받음.
  • ClapTrap의 private 멤버를 protected로 변경하는 이유?
    • 파생 클래스에서 기반 클래스의 멤버 변수에 접근하기 위해.
    • private으로 컴파일하면 아래와 같은 에러가 발생함

      Untitled

  • 파생 클래스에서 초기화 리스트로 초기화할 수 없는 이유?
    • 부모의 생성자가 먼저 호출되어 초기화를 진행하기 때문.
  • 인자를 넘겨줘도 디폴트 생성자로 객체 생성하는 문제

    Untitled

    • 기반 클래스의 디폴트 생성자가 아닌 다른 생성자를 호출하려면 명시적으로 호출해야한다.
  • ClapTrap 소멸자에만 virtual 키워드를 붙이고, 생성자에는 안붙이는 이유?
    • 생성자와 달리 소멸자는 항상 파생클래스가 먼저 호출되어야 하기 때문.
  • ScavTrap 생성자에서의 :ClapTrap(name)의 의미?
    • 기반 클래스의 특정 생성자를 호출하는 것.
    • 디폴트 생성자를 호출하려는 경우에는 필요 없다.

Ex03

주요 개념

다중 상속

  • 두 개 이상의 클래스로부터 멤버를 상속받아 파생 클래스를 생성하는 것.
  • 문제점
    • 상속받은 클래스가 동일한 멤버명을 가질 수 있다.
      • 해결책 : Derived::BaseB()와 같이 어떤 클래스의 멤버를 사용할지 명시해준다.
    • 다이아몬드 상속

다이아몬드 상속

Untitled

  • 다중 상속을 받을 때 이들의 기반 클래스가 동일한 경우
  • 문제점
    • B, C가 겹치지 않더라도 A의 모든 내용이 겹친다.
  • 해결방법
    • B, C가 A를 상속받을 때 public virtual로 상속받는다.(가상 상속)
      • 이를 통해 기반 클래스 A를 한 번만 상속받을 수 있다.

-Wshadow, -Wno-shadow

  • -Wshadow
    • 한 scope에서 선언된 변수가 다른 scope에서도 선언된 경우 경고 발생

Q&A

  • 다중 상속에서 생성자를 정의할 때 :DerivedA(a), DerivedB(b), DerivedC(c)와 같이 기반 클래스의 생성자를 모두 명시적으로 호출해야할까?
    • 디폴트 생성자를 호출하려고 한다면 생략해도 된다.
    • 객체 생성시에 인자를 넣어야 하는 경우는 초기화리스트를 사용해서 호출해야한다.
  • 복사 생성할 때, 변수 접근 방법
    • 직접 접근 vs getter를 통한 접근
    • 변수에 직접 접근하는 것이 더 효율적이다.

전체

Q&A

  • 복사 생성자 내부에서 할당 대입 연산자를 활용하는 방식의 문제점
    • 다음과 같이 기반 클래스의 변수만 복사가 되는 경우를 slicing이라고 한다.
    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
    
      class Base {
      public:
          int x;
          Base& operator=(const Base& other) {
              x = other.x;
              return *this;
          }
      };
    
      class Derived : public Base {
      public:
          int y;
          Derived& operator=(const Derived& other) {
              Base::operator=(other);
              y = other.y;
              return *this;
          }
          Derived(const Derived& other) {
              *this = other;
          }
      };
    
      int main() {
          Derived d1;
          d1.x = 1;
          d1.y = 2;
          Derived d2 = d1; // 여기서 slicing이 발생
          std::cout << d2.x << " " << d2.y << std::endl; // 출력: 1 0
      }
    

Ref.

This post is licensed under CC BY 4.0 by the author.

CPP Module 02 : OCCF, 연산자 오버로딩

CPP Module 04 : 다형성, 추상 클래스