티스토리 뷰

상속의 생존주기

    • 일반적인 상속의 생존주기
      #include <iostream>
      
      class Base {
          public:
          Base() {
              std::cout << "Base()" << std::endl;
          }
          
          ~Base() {
              std::cout << "~Base()" << std::endl;
          }
      };
      
      class Derived : public Base {
          public:
          Derived() {
              std::cout << "Derived()" << std::endl;
          }
          
          ~Derived() {
              std::cout << "~Derived()" << std::endl;
          }
      };
      
      int main() {
          Derived d;
          
          return 0;
      }

      Base() Derived() ~Derived() ~Base()

    • Up-casting 생존주기
      #include <iostream>
      
      class Base {
          public:
          Base() {
              std::cout << "Base()" << std::endl;
          }
          
          ~Base() {
              std::cout << "~Base()" << std::endl;
          }
      };
      
      class Derived : public Base {
          public:
          Derived() {
              std::cout << "Derived()" << std::endl;
          }
          
          ~Derived() {
              std::cout << "~Derived()" << std::endl;
          }
      };
      
      int main() {
          Base* b = new Derived();
          delete b;
          
          return 0;
      }

      Base() Derived() ~Base()

      상위 클래스의 소멸자만 호출되었다. 다음의 경우에서 문제가 될 수 있다.

      class Derived : public Base {
          private:
          int* value = new int; // Never released
          
          public:
          Derived() {
              std::cout << "Derived()" << std::endl;
          }
          
          ~Derived() {
              std::cout << "~Derived()" << std::endl;
              delete value;
          }
      };
      

      Derived의 소멸자가 호출되지 않아 할당된 value가 해제되지 않는다.

가상함수

    • Base에서 함수가 존재할 수도 그렇지 않을 수도 있어야할 때 virtual 기호를 사용한다.이렇게 선언된 함수는 Derived의 함수를 가리지 않는다. 
      #include <iostream>
      
      class Base {
          public:
          virtual void say() {
              std::cout << "Hello" << std::endl;
          }
      };
      
      class Derived : public Base {
          public:
          void say() override {
              std::cout << "World" << std::endl;
          }
      };
      
      int main() {
          Derived d;
          Base& b = d;
          b.say();
          
          return 0;
      }

      World

      상위 클래스의 함수에 virtual 기호를 붙여 하위 클래스의 함수 재정의를 가리지 않도록 한 예시이다. 재정의하는 하위 클래스의 함수에서는 override 기호를 붙여 virtual로 선언된 상위 클래스의 함수를 재정의했음을 명시적으로 나타낼 수 있다.

      참조가 사용되는 이유는 복사 생성자를 이용한 복사의 경우 Derived의 데이터가 유실되어 Base의 새 객체를 만드는 것이지만, 참조를 사용하여 새 Base 객체 생성을 방지하고 Derived 있는 그대로의 주소만 가져다 사용하는 것이다. 하지만 이 경우에도 Base에는 없지만 Derived에 새로 추가된 함수를 사용할 수는 없고 Base에 정의된 함수만을 사용할 수 있다.

      class Derived : public Base {
          public:
          void say() override {
              std::cout << "World" << std::endl;
          }
          
          void foo() {
              std::cout << "FOO" << std::endl;
          }
      };
      
      int main() {
          Derived d;
          Base& b = d;
          b.say();
          b.foo(); // error: ‘class Base’ has no member named ‘foo’
          
          return 0;
      }

      참조를 사용하지 않고 pointer를 이용한 동적할당의 경우도 마찬가지이다.

      int main() {
          Base* b = new Derived();
          b->say();
          delete b;
          
          return 0;
      }

      World

    • 상속의 생존주기 중 up-casting의 생존주기에서 상위 클래스의 소멸자만 호출됨을 확인할 수 있었다. 소멸자도 함수의 일종으로 virtual 기호를 사용하여 하위 클래스에서 재정의된 소멸자를 가리지 않을 수 있다.
      #include <iostream>
      
      class Base {
          public:
          Base() {
              std::cout << "Base()" << std::endl;
          }
          
          virtual ~Base() {
              std::cout << "~Base()" << std::endl;
          }
      };
      
      class Derived : public Base {
          private:
          int* value = new int;
          
          public:
          Derived() {
              std::cout << "Derived()" << std::endl;
          }
          
          ~Derived() {
              std::cout << "~Derived()" << std::endl;
              delete value;
          }
      };
      
      int main() {
          Base* b = new Derived();
          delete b;
          
          return 0;
      }

      Base() Derived() ~Derived() ~Base()


'C++ > C to C++' 카테고리의 다른 글

[C to C++] 상속 - 순수 가상함수, 추상 클래스  (0) 2019.02.03
[C to C++] 상속 - 생존주기, 가상함수  (0) 2019.02.02
[C to C++] 상속  (0) 2019.02.01
[C to C++] 템플릿  (0) 2019.02.01
[C to C++] friend, 연산자 오버로딩  (0) 2019.01.31
[C to C++] 함수 오버로딩  (0) 2019.01.31
댓글
댓글쓰기 폼