December 31, 2008

virtual 소멸자

 

상속하고 있는 클래스의 객체소멸시 문제점

  1. #include <iostream>
    using std::endl;
    using std::cout;
  2. class AAA {
        char* str1;
    public:
        AAA(char* _str1) {
            str1=new char[strlen(_str1)+1];
            strcpy(str1, _str1);
        }
        ~AAA() {        //virtual ~AAA()
            cout<<"~AAA() call!"<<endl;
            delete []str1;
        }
        virtual void showString() {
            cout<<str1<<' ';
        }
    };
  3. class BBB : public AAA {
        char* str2;
    public:
        BBB(char* _str1, char* _str2) : AAA(_str1) {
            str2=new char[strlen(_str2)+1];
            strcpy(str2, _str2);
        }
        ~BBB() {
            cout<<"~BBB() call!"<<endl;
            delete []str2;
        }
        virtual void showString() {
            AAA::showString();
            cout<<str2<<endl;
        }
    };
  4. int main(void) {
        AAA* a=new BBB("Good", "evening");
        BBB* b=new BBB("Good", "morning");
  5.     a->showString();
        b->showString();
  6.     cout<<"----객체 소멸 직전 ----"<<endl;
        delete a;
        delete b;
  7.     return 0;
    }

소멸자의 호출에 문제가 있다. 출력내용을보면 BBB클래스의 소멸자가 한번 덜 호출되었음을 볼 수 있다.
위의 예제에서는 AAA타입 포인터 a로 BBB객체를 가리키고 있다. 그리고 53번째 줄에서는 포인터 a를 통한 BBB객체의 소멸을 시도하고 있다. 여기서 바로 문제가 생긴 것이다. 왜냐하면 포인터 a가 가리키는 객체는 BBB객체이지만 AAA타입의 포인터로 가리키고 있기 때문에, 컴파일러는 BBB객체를 AAA객체로 인식한다. 따라서 AAA클래스의 소멸자만 호출이 되는 것이다.

AAA클래스의 소멸자도, BBB클래스의 소멸자도 동적으로 할당한 메모리 공간을 소멸시켜 주는 역할을 하게끔 정의되어 있기 때문에 객체소멸시에는 반드시 둘 다 호출되어야 한다. 하나라도 호출되지 않으면 메모리 유출(누수)이 발생하게 된다.

Virtual 소멸자

AAA클래스의 소멸자를 다음과 같이 변경한다.

  1. virtual ~AAA() {        //virtual ~AAA()
        cout<<"~AAA() call!"<<endl;
        delete []str1;
    }

일단 AAA클래스의 소멸자를 호출하려 든다. 그러나 소멸자가 Virtual인 관계로 Derived클래스의 소멸자를 호출하게 된다. 비록 함수의 이름은 다르지만, 둘 다 소멸자인 관계로 virtual함수를 오버라이딩했을 때의 현상이 그대로 적용되는 것이다. 그 다음 BBB클래스의 소멸자는 AAA클래스를 상속하고 있기 때문에 다시 AAA클래스의 소멸자가 호출된다. 결국 Derived클래스, Base클래스의 소멸자가 모두 호출이 된다.

 

이 글은 스프링노트에서 작성되었습니다.

No comments:

Post a Comment