[Modern C++] 6.3. virtual 소멸자, 가상함수 테이블, 다중 상속, 가상 상속

윤정민·2023년 7월 4일
0

C++

목록 보기
20/46

1. virtual 소멸자

클래스의 상속을 사용함으로써 소멸자를 가상함수로 만들어야 한다. 아래 코드를 실행하고 문제점을 발견할 수 있다.

#include <iostream>

class Parent {
 public:
  Parent() { std::cout << "Parent 생성자 호출" << std::endl; }
  ~Parent() { std::cout << "Parent 소멸자 호출" << std::endl; }
};
class Child : public Parent {
 public:
  Child() : Parent() { std::cout << "Child 생성자 호출" << std::endl; }
  ~Child() { std::cout << "Child 소멸자 호출" << std::endl; }
};
int main() {
  std::cout << "--- 평범한 Child 만들었을 때 ---" << std::endl;
  { Child c; }
  std::cout << "--- Parent 포인터로 Child 가리켰을 때 ---" << std::endl;
  {
    Parent *p = new Child();
    delete p;
  }
}
  • 실행결과
    • Parent 포인터로 Child를 가리키니 소멸시 Child 소멸자가 호출되지 않음
    • 이를 통해 메모리 누수가 발생할 수 있음
    • 따라서 Parent 소멸자를 virtual로 만들어야 함

2. 가상함수의 구현 원리

지금까지 구현한 내용을 보면 default로 모든 함수를 virtual로 만들면 되지 않을까? 라는 의문이 생긴다. 하지만 이는 가상함수를 사용하게 되면 약간의 오버헤드(overhead)가 존재하기 때문에 사용하지 않는다.

2.1. 가상함수 테이블

  • C++ 컴파일러는 가상함수가 하나라도 존재하는 클래스에 대해, 가상함수 테이블을 만들게 됨
    • 가상 함수 테이블은 전화 번호부라고 생각하자
    • 가상 함수 테이블에는 함수의 이름과 실제로 어떤 함수가 대응되는지 테이블로 저장하고 있음
  • 예제
    • 아래 코드의 내용은 다음과 같이 표현할 수 있음
class Parent {
 public:
  virtual void func1();
  virtual void func2();
};
class Child : public Parent {
 public:
  virtual void func1();
  void func3();
};

2.2. 가상함수의 실행 동작 원리

Parent* p = Parent();
p->func1();
  • 가상 함수를 호출
  • pParent를 가리키는 포인터 이니, func1()의 정의를 Parent 클래스에서 찾음
  • func1()이 가상함수임을 인지
  • func1()을 직접실행하지 않고, 가상함수 테이블에서 func1()에 해당하는 함수를 찾음
  • Parent::func1()를 호출

3. 순수 가상 함수와 추상 클래스

3.1. 순수 가상 함수

  • 함수의 몸통이 정의되어 있지 않고 단순히 =0;으로 처리되어있는 가상함수
  • 해당함수는 반드시 오버라이딩 외어야만 하는 함수
  • 해당 함수를 선언한 클래스의 객체를 생성하는 것불가능
  • 해당 함수를 호출하는것 또한 불가능

3.2. 추상 클래스

  • 순수 가상함수를 최소 한개 포함하고 있는 클래스
  • 반드시 상속되어야 하는 클래스

4. 다중상속

  • 한 클래스가 다른 여러 개의 클래스들을 상속 받는 것
    • c++에서는 허용
  • 상속된 클래스의 생성자는 상속된 순서대로 호출됨
  • 상속되는 두 클래스에 같은 이름의 변수가 없도록 주의할것
  • 다이아몬드 상속을 주의할것
class A {
 public:
  int a;
};

class B {
 public:
  int b;
};

class C : public A, public B {
 public:
  int c;
};
profile
그냥 하자

0개의 댓글